# set the root to the project directory, not the rmd directory
knitr::opts_knit$set(root.dir = rprojroot::find_rstudio_root_file())
# default to not printing the code
knitr::opts_chunk$set(echo = FALSE)
# libraries
library(tidyverse)
package 㤼㸱tidyverse㤼㸲 was built under R version 4.0.5Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
-- Attaching packages ------------------------------------------------------------ tidyverse 1.3.1 --
v ggplot2 3.3.3 v purrr 0.3.4
v tibble 3.1.2 v dplyr 1.0.6
v tidyr 1.1.3 v stringr 1.4.0
v readr 1.4.0 v forcats 0.5.1
package 㤼㸱ggplot2㤼㸲 was built under R version 4.0.3package 㤼㸱tibble㤼㸲 was built under R version 4.0.5package 㤼㸱tidyr㤼㸲 was built under R version 4.0.5package 㤼㸱readr㤼㸲 was built under R version 4.0.3package 㤼㸱dplyr㤼㸲 was built under R version 4.0.5package 㤼㸱forcats㤼㸲 was built under R version 4.0.3-- Conflicts --------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
library(sf)
Linking to GEOS 3.9.0, GDAL 3.2.1, PROJ 7.2.1
library(stars)
package 㤼㸱stars㤼㸲 was built under R version 4.0.5Loading required package: abind
library(tmap)
package 㤼㸱tmap㤼㸲 was built under R version 4.0.5Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
library(transformr) # not needed for this doc at present?
package 㤼㸱transformr㤼㸲 was built under R version 4.0.5
Attaching package: 㤼㸱transformr㤼㸲
The following object is masked from 㤼㸱package:sf㤼㸲:
st_normalize
library(gganimate) # not needed here at present
package 㤼㸱gganimate㤼㸲 was built under R version 4.0.5
library(viridis)
package 㤼㸱viridis㤼㸲 was built under R version 4.0.5Loading required package: viridisLite
package 㤼㸱viridisLite㤼㸲 was built under R version 4.0.5
library(colorspace)
package 㤼㸱colorspace㤼㸲 was built under R version 4.0.5
# source in the data management
# source('directorySet.R')
source(file.path('Scripts', 'Scenarios', 'plotting', 'metabolismLocalAndStatic.R'))
sysname release version nodename machine
"Windows" "10 x64" "build 19042" "DESKTOP-NU5UDHD" "x86-64"
login user effective_user
"Galen" "Galen" "Galen"
Purpose here is primarily to go through some plots, look at them, and make static versions for the paper. This is mostly a copy-paste and translate over from metabolismLocalAndStatic. I’ve done this to split out the data read-in, function definitions, and plotting (and particularly the plot trying-out). I’ve been using these notebooks for plot testing, because it’s really nice to be able to scroll around and see what we’ve done, rather than have to keep re-making plot objects when we forget what they look like.
The catch with this approach is the quick and dirty prototyping isn’t quite so quick, and this document ends up taking FOREVER to load. Might switch back? But it sure is nice to actually see what each figure I made looks like, especially when we’re likely to drop this for extended periods.
Set the date for examples
availDays <- st_get_dimension_values(weraiCropTemp, which = 'time')
datewanted <- as.character(availDays[17])
Static versions with drivers and outcomes
Make a static version using the tmap functions
suppressMessages(tmap_mode('plot'))
allfun(tempObj = weraiCropTemp, tempAtt = 1,
inunObj = weraiCropInun, inunAtt = 1,
gppObj = weraiCropPredGPP, gppAtt = 1,
erObj = weraiCropPredER, erAtt = 1,
datewanted)


Clean that up just a bit, with a grey background. probably pull the title off but it’s nice to have as reference while i’m making these
tm_grid_static <- tmap_arrange(tempfun(weraiCropTemp, 1, datewanted) +
tm_layout(bg.color = "grey85"),
inunfun(weraiCropInun, 1, datewanted, titled = FALSE) +
tm_layout(bg.color = "grey85"),
gppfun(weraiCropPredGPP, 1, datewanted, titled = FALSE) +
tm_layout(bg.color = "grey85"),
erfun(weraiCropPredER, 1, datewanted, titled = FALSE) +
tm_layout(bg.color = "grey85"))
tm_grid_static

I think for completeness let’s make a ggplot version too and see which is better. Takes more work, but have more control (probably just because I speak ggplot)
gg_grid_static <- ggpubr::ggarrange(
tempfun(weraiCropTemp, 1, datewanted, plotPkg = 'ggplot') +
guides(fill = guide_legend(title.position = 'top')) +
theme_grey(base_size = 8) +
theme(legend.position = 'bottom',
legend.background = element_blank(),
legend.key.size = unit(0.3, 'cm')),
inunfun(weraiCropInun, 1, datewanted, titled = FALSE, plotPkg = 'ggplot') +
guides(fill = guide_legend(title.position = 'top')) +
theme_grey(base_size = 8) +
theme(legend.position = 'bottom',
legend.background = element_blank(),
legend.key.size = unit(0.3, 'cm')),
gppfun(weraiCropPredGPP, 1, datewanted, titled = FALSE, plotPkg = 'ggplot') +
guides(fill = guide_legend(title.position = 'top')) +
theme_grey(base_size = 8) +
theme(legend.position = 'bottom',
legend.background = element_blank(),
legend.key.size = unit(0.3, 'cm')),
erfun(weraiCropPredER, 1, datewanted, titled = FALSE, plotPkg = 'ggplot') +
guides(fill = guide_legend(title.position = 'top')) +
theme_grey(base_size = 8) +
theme(legend.position = 'bottom',
legend.background = element_blank(),
legend.key.size = unit(0.3, 'cm')),
ncol = 2, nrow = 2)
print(gg_grid_static)

Code block to print and make those into figs
pdf(file.path(scriptOut, 'Werai_tm.pdf'),
onefile = FALSE, height = 12/2.54, width = 16/2.54, useDingbats = FALSE)
print(tm_grid_static)
dev.off()
null device
1
png(file.path(scriptOut, 'Werai_tm.png'),
height = 12/2.54, width = 16/2.54, units = 'in', res = 300)
print(tm_grid_static)
dev.off()
null device
1
# Can I print those?
pdf(file.path(scriptOut, 'Werai_gg.pdf'),
onefile = FALSE, height = 12/2.54, width = 16/2.54, useDingbats = FALSE)
print(gg_grid_static)
dev.off()
null device
1
png(file.path(scriptOut, 'Werai_gg.png'),
height = 12/2.54, width = 16/2.54, units = 'in', res = 300)
print(gg_grid_static)
dev.off()
null device
1
Uncertainty
I think now that I have the functions, there’s a slicker way to do this, but I don’t want to reinvent the wheel at this point. Might want to turn this into a function?
ER
# ER
er_sf <- weraiCropPredER[1,,] %>%
st_as_sf() %>%
select(all_of(datewanted)) %>%
rename(ER = 1) %>%
mutate(logER = log10(1+ER), type = 'estimate')
er_sfPU <- weraiCropPredER[2,,] %>%
st_as_sf() %>%
select(all_of(datewanted)) %>%
rename(ER = 1) %>%
mutate(logER = log10(1+ER), type = 'upper')
er_sfPL <- weraiCropPredER[3,,] %>%
st_as_sf() %>%
select(all_of(datewanted)) %>%
rename(ER = 1) %>%
mutate(logER = log10(1+ER), type = 'lower')
er_sf_LMU <- bind_rows(er_sf, er_sfPU, er_sfPL) %>%
mutate(namedPI = ifelse(type == 'lower', "Lower 95% PI",
ifelse(type == 'estimate', "Estimate",
ifelse(type == 'upper', "Upper 95% PI",
'SCREWUP'))))
erlabel <- 'ER (kg 02/day)\nat max extent'
# Can get away with this because pretty ranges work out OK
erControl <- ersetup(data = weraiCropPredER, attnum = 1)
er_gg_uncertain <- ggplot() +
geom_sf(data = er_sf_LMU, mapping = aes(fill = logER), color = NA) +
# geom_sf_label(data = ltimNoNorth, mapping = aes(label = ValleyName)) +
coord_sf() +
# Closest to the tmap
scale_fill_stepsn(colors = erControl$erpal,
breaks = erControl$erbreaks[2:length(erControl$erbreaks)],
limits = c(min(erControl$erbreaks), max(erControl$erbreaks)),
labels = erControl$erlabels,
guide = 'legend',
name = erlabel) +
facet_grid(fct_reorder(namedPI, .x = logER, .fun = max)~.) # lower, estimat and upper should always fall in that order for their maxes
er_gg_uncertain

GPP
# GPP
# I'm sure thgppe's a slick way to select all three attributes and do this in one
# go, but I just need to get this done
gpp_sf <- weraiCropPredGPP[1,,] %>%
st_as_sf() %>%
select(all_of(datewanted)) %>%
rename(GPP = 1) %>%
mutate(logGPP = log10(1+GPP), type = 'estimate')
gpp_sfPU <- weraiCropPredGPP[2,,] %>%
st_as_sf() %>%
select(all_of(datewanted)) %>%
rename(GPP = 1) %>%
mutate(logGPP = log10(1+GPP), type = 'upper')
gpp_sfPL <- weraiCropPredGPP[3,,] %>%
st_as_sf() %>%
select(all_of(datewanted)) %>%
rename(GPP = 1) %>%
mutate(logGPP = log10(1+GPP), type = 'lower')
gpp_sf_LMU <- bind_rows(gpp_sf, gpp_sfPU, gpp_sfPL) %>%
mutate(namedPI = ifelse(type == 'lower', "Lower 95% PI",
ifelse(type == 'estimate', "Estimate",
ifelse(type == 'upper', "Upper 95% PI",
'SCREWUP'))))
gpplabel <- 'GPP (kg 02/day)\nat max extent'
gppControl <- gppsetup(weraiCropPredGPP, attnum = 1)
gpp_gg_uncertain <- ggplot() +
geom_sf(data = gpp_sf_LMU, mapping = aes(fill = logGPP), color = NA) +
# geom_sf_label(data = ltimNoNorth, mapping = aes(label = ValleyName)) +
coord_sf() +
# Closest to the tmap
scale_fill_stepsn(colors = gppControl$gpppal,
breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
limits = c(min(gppControl$gppbreaks), max(gppControl$gppbreaks)),
labels = gppControl$gpplabels,
guide = 'legend',
name = gpplabel) +
facet_grid(fct_reorder(namedPI, .x = logGPP, .fun = max)~.) # lower, estimat and uppgpp should always fall in that ordgpp for their maxes
gpp_gg_uncertain

Combine the ER and GPP and save as figures
both_uncertain <- ggpubr::ggarrange(gpp_gg_uncertain +
guides(fill = guide_legend(title.position = 'top')) +
theme_grey(base_size = 8) +
theme(legend.position = 'bottom',
legend.background = element_blank(),
legend.key.size = unit(0.3, 'cm')),
er_gg_uncertain +
guides(fill = guide_legend(title.position = 'top')) +
theme_grey(base_size = 8) +
theme(legend.position = 'bottom',
legend.background = element_blank(),
legend.key.size = unit(0.3, 'cm')),
ncol = 2, nrow = 1)
both_uncertain
# Just print the ggplots
# Can I print those?
pdf(file.path(scriptOut, 'Werai_uncertainty.pdf'),
onefile = FALSE, height = 12/2.54, width = 16/2.54, useDingbats = FALSE)
print(both_uncertain)
dev.off()
png
2
png(file.path(scriptOut, 'Werai_uncertainty.png'),
height = 12/2.54, width = 16/2.54, units = 'in', res = 300)
print(both_uncertain)
dev.off()
png
2

Bar charts
make a wide version of the data so I can have mins and maxes OR, should I do all of them and fct_order them?
Joining seems safe, but geographic joins are a mess. It doesn’t work at all. binding cols is actually safer and works
GPP
gpp_sf_LMU_wide <- bind_cols(gpp_sf[,-4],
st_drop_geometry(rename(gpp_sfPU[,-c(4)],
UGPP = GPP,
upper_logGPP = logGPP)),
st_drop_geometry(rename(gpp_sfPL[,-4],
LGPP = GPP,
lower_logGPP = logGPP))) %>%
mutate(wetlandID = row_number())
Maybe for a subset of wetlands?
# Grab some set of wetlands
which(gpp_sf$geometry == gpp_sf_LMU$geometry[3])
[1] 3
exampleWets <- c(1:100)
bargpp <- ggplot(gpp_sf_LMU_wide[exampleWets, ],
aes(x = wetlandID, y = logGPP, fill = logGPP)) +
geom_col() + # the geom_bar equivalent when it's not counting cases.
geom_errorbar(mapping = aes(ymin = lower_logGPP, ymax = upper_logGPP)) +
scale_fill_stepsn(colors = gppControl$gpppal,
breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
limits = c(min(gppControl$gppbreaks), max(gppControl$gppbreaks)),
labels = gppControl$gpplabels,
guide = 'legend',
name = gpplabel) +
scale_y_continuous(breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
labels = round(10^(gppControl$gppbreaks[2:length(gppControl$gppbreaks)]))) +
labs(x = 'Wetland', y = gpplabel)
bargpp

I assume it is a mes to just throw them all on actually, with a fair amount of monkeying with the look, that’s OK
bargppall <- ggplot(gpp_sf_LMU_wide,
aes(x = fct_reorder(as.factor(wetlandID), logGPP, .desc = TRUE), y = logGPP, fill = logGPP)) +
geom_col() + # the geom_bar equivalent when it's not counting cases.
geom_linerange(mapping = aes(ymin = lower_logGPP, ymax = upper_logGPP),
color = 'grey50', alpha = 0.2) +
scale_fill_stepsn(colors = gppControl$gpppal,
breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
limits = c(min(gppControl$gppbreaks), max(gppControl$gppbreaks)),
labels = gppControl$gpplabels,
guide = 'legend',
name = gpplabel) +
scale_y_continuous(breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
labels = round(10^(gppControl$gppbreaks[2:length(gppControl$gppbreaks)]))) +
labs(x = 'Wetland', y = gpplabel)
bargppall

I actually like that that encompasses an area that integrates to total production across the Werai
I can do points as below, but the integration implied above is nice
bargppallpoint <- ggplot(gpp_sf_LMU_wide,
aes(x = fct_reorder(as.factor(wetlandID), logGPP),
y = logGPP, color = logGPP)) +
geom_linerange(mapping = aes(ymin = lower_logGPP, ymax = upper_logGPP), color = 'grey50') +
geom_point() + # the geom_bar equivalent when it's not counting cases.
scale_color_stepsn(colors = gppControl$gpppal,
breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
limits = c(min(gppControl$gppbreaks), max(gppControl$gppbreaks)),
labels = gppControl$gpplabels,
guide = 'legend',
name = gpplabel) +
scale_y_continuous(breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
labels = round(10^(gppControl$gppbreaks[2:length(gppControl$gppbreaks)]))) +
labs(x = 'Wetland', y = gpplabel)
bargppallpoint

ER
Setup block. Again, this could be sorted with a function, but right now just copy-pasting
erlabel <- 'GPP (kg 02/day)\nat max extent'
er_sf_LMU_wide <- bind_cols(er_sf[,-4],
st_drop_geometry(rename(er_sfPU[,-c(4)],
UER = ER,
upper_logER = logER)),
st_drop_geometry(rename(er_sfPL[,-4],
LER = ER,
lower_logER = logER))) %>%
mutate(wetlandID = row_number())
Barplot
barerall <- ggplot(er_sf_LMU_wide,
aes(x = fct_reorder(as.factor(wetlandID), logER, .desc = TRUE), y = logER, fill = logER)) +
geom_col() + # the geom_bar equivalent when it's not counting cases.
geom_linerange(mapping = aes(ymin = lower_logER, ymax = upper_logER),
color = 'grey50', alpha = 0.2) +
scale_fill_stepsn(colors = erControl$erpal,
breaks = erControl$erbreaks[2:length(erControl$erbreaks)],
limits = c(min(erControl$erbreaks), max(erControl$erbreaks)),
labels = erControl$erlabels,
guide = 'legend',
name = erlabel) +
scale_y_continuous(breaks = erControl$erbreaks[2:length(erControl$erbreaks)],
labels = round(10^(erControl$erbreaks[2:length(erControl$erbreaks)]))) +
labs(x = 'Wetland', y = erlabel)
barerall

Both together, with GPP up and ER down
Setup
# Can I make one with them both there going opposite direction?
both_sf_LMU_wide <- bind_cols(mutate(gpp_sf_LMU_wide),
mutate(st_drop_geometry(er_sf_LMU_wide[,-c(8)])))
# Need new labels and breaks. Could cobble, but getting confusing and misaligned
# bothbreaks_log <- c(-rev(erbreaks_log[2:length(erbreaks_log)]), gppbreaks_log)
# # and those breaks might not quite yield 10, so maximise the palette differences
# erpal_log <- sequential_hcl(length(erbreaks_log)-1, palette = 'Purples', rev = TRUE)
# I think here I want continuous colors. but maybe still a broken up legend?
# have to do the negatives before delogging
# bothlabels_log <- c(-10^rev(erbreaks_log), 10^gppbreaks_log)
#
# bothlabels_log <- format(bothlabels_log, big.mark=",",
# scientific=FALSE, trim = TRUE, digits = 0)
# This is really getting complex. Why don't I just use 0,1,10,100,1000,10000?
# They've both been shifted by 1 to log, so
# This is just used to get the labels, the actual log-scale is plotted and so the zeros are done correctly
bothbreaks_log <- c(-10^(4:0), 10^(1:4))
bothbreaks_log[5] <- 0 # Because both were shifted so 1 = 0
bothlabels_log <- as.character(bothbreaks_log)
# erstart <- erlabels_log[1:(length(erlabels_log)-1)]
# erstart[1] <- "0" # instead of 1
# bothlabels_log <- paste0(erstart, ' to ', erlabels_log[2:length(erlabels_log)])
# erlabels_log
# AAAA try to get some lables for the x. I JUST WANT IT TO HAVE THE NUMBER BUT IT WON"T DO IT
reordx <- fct_reorder(as.factor(both_sf_LMU_wide$wetlandID),
both_sf_LMU_wide$logGPP, .desc = TRUE)
# I'm confused. that didn't work. this is anoyuting
Try a plot
barboth <- ggplot(both_sf_LMU_wide) +
geom_col(mapping = aes(x = fct_reorder(as.factor(wetlandID),
logER, .desc = TRUE),
y = -logER, fill = -logER)) + # the geom_bar equivalent when it's not counting cases.
geom_linerange(mapping = aes(x = fct_reorder(as.factor(wetlandID),
logER, .desc = TRUE),
ymin = -lower_logER, ymax = -upper_logER),
color = 'grey50', alpha = 0.2) +
# scale_fill_stepsn(colors = erpal_log,
# breaks = erbreaks_log[2:length(erbreaks_log)],
# limits = c(min(erbreaks_log), max(erbreaks_log)),
# labels = erlabels_log,
# guide = 'legend',
# name = erlabel) +
# scale_fill_stepsn(colors = c(rev(erpal_log), gpppal_log),
# breaks = c(-rev(erbreaks_log[2:length(erbreaks_log)]), 0,
# gppbreaks_log[2:length(gppbreaks_log)]),
# limits = c(min(-erbreaks_log), max(gppbreaks_log)),
# # labels = c(erlabels_log, gpplabels_log),
# guide = 'legend',
# name = 'kg O2\nat max extent') +
geom_col(mapping = aes(x = fct_reorder(as.factor(wetlandID),
logGPP, .desc = TRUE),
y = logGPP, fill = logGPP)) +
geom_linerange(mapping = aes(x = fct_reorder(as.factor(wetlandID),
logGPP, .desc = TRUE),
ymin = lower_logGPP, ymax = upper_logGPP),
color = 'grey50', alpha = 0.2) +
geom_line(mapping = aes(x = fct_reorder(as.factor(wetlandID),
logGPP, .desc = TRUE),
y = logGPP-logER, group = NA)) +
# This palette is very slightly different because it's not binned and GPP above uses Emerald instead of green, but it's sure close and way easier
scale_fill_continuous_diverging(palette = "Purple-Green",
limits = c(-4, 4),
breaks = -4:4,
labels = bothlabels_log) +
scale_y_continuous(limits = c(-4, 4),
breaks = -4:4,
labels = bothlabels_log) +
# scale_y_continuous(breaks = c(-erbreaks_log[2:length(erbreaks_log)],
# gppbreaks_log[2:length(gppbreaks_log)]),
# labels = c(-round(10^(erbreaks_log[2:length(erbreaks_log)])),
# round(10^(gppbreaks_log[2:length(gppbreaks_log)])))) +
labs(x = 'Wetland (ordered by GPP)', y = 'kg O2', fill = 'kg O2') +
# argh doesn't work because has been reordered
# scale_x_discrete(breaks = as.character(c(1, 250, 500, 750, 1000))) +
theme(legend.position = c(0.75, 0.54)) +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
legend.position = c(0.75, 0.55))
barboth

The inability to label x in a reasonable way is infuriating. Can I do it differently? Try making a labelled dataset that’s arranged how I was doing fct_reorder.
both_sf_LMU_wide2 <- both_sf_LMU_wide %>%
arrange(desc(logGPP)) %>%
mutate(GPPrank = row_number())
Make the plot. Interesting that the notebook plotter does a worse job than the plots panel for a script. The funny gaps aren’t really there- to see, run barboth in the console.
barboth <- ggplot(both_sf_LMU_wide2) +
geom_col(mapping = aes(x = GPPrank,
y = -logER, fill = -logER)) + # the geom_bar equivalent when it's not counting cases.
geom_linerange(mapping = aes(x = GPPrank,
ymin = -lower_logER, ymax = -upper_logER),
color = 'grey50', alpha = 0.2) +
geom_col(mapping = aes(x = GPPrank,
y = logGPP, fill = logGPP)) +
geom_linerange(mapping = aes(x = GPPrank,
ymin = lower_logGPP, ymax = upper_logGPP),
color = 'grey50', alpha = 0.2) +
geom_line(mapping = aes(x = GPPrank,
y = logGPP-logER, group = NA)) +
# This palette is very slightly different because it's not binned and GPP above uses Emerald instead of green, but it's sure close and way easier
scale_fill_continuous_diverging(palette = "Purple-Green",
limits = c(-4, 4),
breaks = -4:4,
labels = bothlabels_log) +
scale_y_continuous(limits = c(-4, 4),
breaks = -4:4,
labels = bothlabels_log) +
labs(x = 'Wetland (ordered by GPP)', y = 'kg O2', fill = 'kg O2') +
# scale_x_discrete(breaks = c(1, 250, 500, 750, 1000)) +
theme_bw(base_size = 8) + theme(legend.position = c(0.75, 0.53),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank())
barboth

Save that as a figure
pdf(file.path(scriptOut, 'Werai_mirrorgram.pdf'),
onefile = FALSE, height = 8/2.54, width = 12/2.54, useDingbats = FALSE)
print(barboth)
dev.off()
null device
1
png(file.path(scriptOut, 'Werai_mirrorgram.png'),
height = 8/2.54, width = 12/2.54, units = 'in', res = 300)
print(barboth)
dev.off()
null device
1
What about Darren’s fingerprints? They would maybe take the GPP and ER and make a density with them? OUt of what? The wetlands? Could work. Would need to sort out the weighting by volume. it’s already in there, but that means it will give each location the same weight. I think a better thing for the fingerprints would be to remove it, and then give each wetland its predicted per liter rate and weight by volume IE use the straight predictions and then weight by inundaton Should be straightforward, but likely won’t be
Would be a really cool way to look at scenarios. especially if I can do it for whole catchments
BUT, because GPP and ER are both linear fits of temp, they will exactly predict each other according to a linear relationship, and so there won’t be any 2-d variation and all the points will fall on a line. IE for a given GPP there will only be one ER, and so the fingerprint will be a line. Cool idea, but we’d need more info about their variance relative to each other
Annual reporting
What about making some examples to illustrate annual (or arbitrary time period) reporting?
First, establish the time periods and do the aggregations and other data organisation
interDates <- as.POSIXct(c("2014-06-30", "2015-06-30", "2016-06-30", "2017-06-30", "2018-06-30", "2019-06-30"))
tempannual <- tempaggregate(weraiCropTemp, by_t = as.Date(interDates), FUN = mean, na.rm = TRUE)
inunannual <- tempaggregate(weraiCropInun, by_t = as.Date(interDates), FUN = sum, na.rm = TRUE)
gppannual <- tempaggregate(weraiCropPredGPP[1,,], by_t = as.Date(interDates), FUN = sum, na.rm = TRUE)
erannual <- tempaggregate(weraiCropPredER[1,,], by_t = as.Date(interDates), FUN = sum, na.rm = TRUE)
# Data organisation
# AHHH the flopped dims
if (attributes(st_dimensions(gppannual))$name[1] != 'geometry') {
gppannual <- aperm(gppannual, c(2,1))
}
if (attributes(st_dimensions(erannual))$name[1] != 'geometry') {
erannual <- aperm(erannual, c(2,1))
}
# GPP
gppYear_sf <- gppannual %>%
st_as_sf() %>%
pivot_longer(cols = -geometry, names_to = 'WaterYear', values_to = 'GPP') %>%
mutate(logGPP = log10(1+GPP)) %>%
st_as_sf() # REALLY???
number of items to replace is not a multiple of replacement length
gppYear_sf
Simple feature collection with 5815 features and 3 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 1086148 ymin: -3924954 xmax: 1148710 ymax: -3893940
Projected CRS: GDA94 / Australian Albers
max(gppYear_sf$logGPP) # is within
[1] 3.412777
gppControl$gppbreaks
[1] 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0
# ER
erYear_sf <- erannual %>%
st_as_sf() %>%
pivot_longer(cols = -geometry, names_to = 'WaterYear', values_to = 'ER') %>%
mutate(logER = log10(1+ER)) %>%
st_as_sf() # REALLY???
number of items to replace is not a multiple of replacement length
erYear_sf
Simple feature collection with 5815 features and 3 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 1086148 ymin: -3924954 xmax: 1148710 ymax: -3893940
Projected CRS: GDA94 / Australian Albers
# the range should still work for tthe colors
max(erYear_sf$logER) # is within
[1] 3.779558
erControl$erbreaks
[1] 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0
I don’t think I use this, but I did make a full-werai aggregation
# aggregate to werai
# temp area-weighted
areas <- tempannual %>%
st_geometry() %>%
st_area() %>%
as.numeric()
tempW <- catchAgg <- catchAggW(strict = tempannual, strictWeights = areas,
FUN = mean, summaryPoly = ramsarW1)
inunW <- aggregate(inunannual,
by = ramsarW1,
FUN = sum, na.rm = TRUE)
gppW <- aggregate(gppannual,
by = ramsarW1,
FUN = sum, na.rm = TRUE)
erW <- aggregate(erannual,
by = ramsarW1,
FUN = sum, na.rm = TRUE)
Tmap Plots
Make a facetted tmap
Again, can I do this by modifying what I pass to the plotting functions? Almost certainly
The units are weird, because this is added up across bimonths. It’s neither the total or the average.Not really sure what to call it
Change the tmap_mode() depending on the purpose. DO NOT CHANGE TO VIEW AND TRY TO RUN HERE. IF YOU WANT TO VIEW, CHANGE AND RUN IN CONSOLE. The markdown will run it, but incredibly slowly.
GPP
tmap_mode('plot')
tmap mode set to plotting
gppyrlabel <- 'Total Yearly GPP (kg 02)\nat max bimonth extents'
gppAnnual_tm <- gppYear_sf %>%
filter(WaterYear != '2014-06-29') %>% # because a 5-panel is ugly
tm_shape() +
tm_fill(col = 'logGPP',
palette = gppControl$gpppal,
breaks = gppControl$gppbreaks,
labels = gppControl$gpplabels,
title = gppyrlabel) +
tm_facets(by = 'WaterYear')
gppAnnual_tm

ER
eryrlabel <- 'Total Yearly ER (kg 02)\nat max bimonth extents'
erAnnual_tm <- erYear_sf %>%
filter(WaterYear != '2014-06-29') %>% # because a 5-panel is ugly
tm_shape() +
tm_fill(col = 'logER',
palette = erControl$erpal,
breaks = erControl$erbreaks,
labels = erControl$erlabels,
title = eryrlabel) +
tm_facets(by = 'WaterYear')
erAnnual_tm

GGPLOT
gpp
gppAnnual_gg <- gppYear_sf %>%
filter(WaterYear != '2014-06-29') %>% # because a 5-panel is ugly
ggplot() +
geom_sf(mapping = aes(fill = logGPP), color = NA) +
coord_sf() +
# Closest to the tmap
scale_fill_stepsn(colors = gppControl$gpppal,
breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
limits = c(min(gppControl$gppbreaks), max(gppControl$gppbreaks)),
labels = gppControl$gpplabels,
guide = 'legend',
name = gppyrlabel) +
facet_wrap(vars(WaterYear))
gppAnnual_gg

ER
erAnnual_gg <- erYear_sf %>%
filter(WaterYear != '2014-06-29') %>% # because a 5-panel is ugly
ggplot() +
geom_sf(mapping = aes(fill = logER), color = NA) +
coord_sf() +
# Closest to the tmap
scale_fill_stepsn(colors = erControl$erpal,
breaks = erControl$erbreaks[2:length(erControl$erbreaks)],
limits = c(min(erControl$erbreaks), max(erControl$erbreaks)),
labels = erControl$erlabels,
guide = 'legend',
name = eryrlabel) +
facet_wrap(vars(WaterYear))
erAnnual_gg

Stack 3 years of gpp and ER together for the document
gppAnnual_gg3 <- gppYear_sf %>%
filter(WaterYear != '2014-06-29' & WaterYear != '2018-06-29') %>% # because a 5-panel is ugly
ggplot() +
geom_sf(mapping = aes(fill = logGPP), color = NA) +
coord_sf() +
# Closest to the tmap
scale_fill_stepsn(colors = gppControl$gpppal,
breaks = gppControl$gppbreaks[2:length(gppControl$gppbreaks)],
limits = c(min(gppControl$gppbreaks), max(gppControl$gppbreaks)),
labels = gppControl$gpplabels,
guide = 'legend',
name = gppyrlabel) +
facet_grid(WaterYear~.) +
theme(legend.position = 'bottom')
# gppAnnual_gg3
erAnnual_gg3 <- erYear_sf %>%
filter(WaterYear != '2014-06-29' & WaterYear != '2018-06-29') %>% # because a 5-panel is ugly
ggplot() +
geom_sf(mapping = aes(fill = logER), color = NA) +
coord_sf() +
# Closest to the tmap
scale_fill_stepsn(colors = erControl$erpal,
breaks = erControl$erbreaks[2:length(erControl$erbreaks)],
limits = c(min(erControl$erbreaks), max(erControl$erbreaks)),
labels = erControl$erlabels,
guide = 'legend',
name = eryrlabel) +
facet_grid(WaterYear~.) +
theme(legend.position = 'bottom')
# erAnnual_gg3
annualGPPER <- ggpubr::ggarrange(gppAnnual_gg3 +
guides(fill = guide_legend(title.position = 'top')) +
theme_grey(base_size = 8) +
theme(legend.position = 'bottom',
legend.background = element_blank(),
legend.key.size = unit(0.3, 'cm')),
erAnnual_gg3 +
guides(fill = guide_legend(title.position = 'top')) +
theme_grey(base_size = 8) +
theme(legend.position = 'bottom',
legend.background = element_blank(),
legend.key.size = unit(0.3, 'cm')),
ncol = 2, nrow = 1)
annualGPPER

Print out the ggplots for the doc
# Just print the ggplots
# Can I print those?
pdf(file.path(scriptOut, 'Werai_gg_Annual.pdf'),
onefile = FALSE, height = 12/2.54, width = 16/2.54, useDingbats = FALSE)
print(annualGPPER)
dev.off()
null device
1
png(file.path(scriptOut, 'Werai_gg_Annual.png'),
height = 12/2.54, width = 16/2.54, units = 'in', res = 300)
print(annualGPPER)
dev.off()
null device
1
LS0tDQp0aXRsZTogIkxvY2FsIE1ldGFib2xpc20gUGxvdHMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCmBgYHtyIHNldHVwfQ0KIyBzZXQgdGhlIHJvb3QgdG8gdGhlIHByb2plY3QgZGlyZWN0b3J5LCBub3QgdGhlIHJtZCBkaXJlY3RvcnkNCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gcnByb2pyb290OjpmaW5kX3JzdHVkaW9fcm9vdF9maWxlKCkpDQojIGRlZmF1bHQgdG8gbm90IHByaW50aW5nIHRoZSBjb2RlDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEZBTFNFKQ0KDQojIGxpYnJhcmllcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShzdGFycykNCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkodHJhbnNmb3JtcikgIyBub3QgbmVlZGVkIGZvciB0aGlzIGRvYyBhdCBwcmVzZW50Pw0KbGlicmFyeShnZ2FuaW1hdGUpICMgbm90IG5lZWRlZCBoZXJlIGF0IHByZXNlbnQNCmxpYnJhcnkodmlyaWRpcykNCmxpYnJhcnkoY29sb3JzcGFjZSkNCg0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQojIHNvdXJjZSBpbiB0aGUgZGF0YSBtYW5hZ2VtZW50DQoNCiMgS2luZCBvZiBoYWNreSBjaGVjayB0byBvbmx5IHJ1biBpZiBuZWVkZWQNCmlmICghKCd3ZXJhaUNyb3BJbnVuJyAlaW4lIGxzKCkpKSB7DQogICAgc291cmNlKGZpbGUucGF0aChoZXJlOjpoZXJlKCksICdTY3JpcHRzJywgJ1NjZW5hcmlvcycsICdwbG90dGluZycsICdtZXRhYm9saXNtTG9jYWxBbmRTdGF0aWMuUicpKQ0KfQ0KDQpgYGANCg0KUHVycG9zZSBoZXJlIGlzIHByaW1hcmlseSB0byBnbyB0aHJvdWdoIHNvbWUgcGxvdHMsIGxvb2sgYXQgdGhlbSwgYW5kIG1ha2Ugc3RhdGljIHZlcnNpb25zIGZvciB0aGUgcGFwZXIuDQpUaGlzIGlzIG1vc3RseSBhIGNvcHktcGFzdGUgYW5kIHRyYW5zbGF0ZSBvdmVyIGZyb20gbWV0YWJvbGlzbUxvY2FsQW5kU3RhdGljLiBJJ3ZlIGRvbmUgdGhpcyB0byBzcGxpdCBvdXQgdGhlIGRhdGEgcmVhZC1pbiwgZnVuY3Rpb24gZGVmaW5pdGlvbnMsIGFuZCBwbG90dGluZyAoYW5kIHBhcnRpY3VsYXJseSB0aGUgcGxvdCB0cnlpbmctb3V0KS4gSSd2ZSBiZWVuIHVzaW5nIHRoZXNlIG5vdGVib29rcyBmb3IgcGxvdCB0ZXN0aW5nLCBiZWNhdXNlIGl0J3MgcmVhbGx5IG5pY2UgdG8gYmUgYWJsZSB0byBzY3JvbGwgYXJvdW5kIGFuZCBzZWUgd2hhdCB3ZSd2ZSBkb25lLCByYXRoZXIgdGhhbiBoYXZlIHRvIGtlZXAgcmUtbWFraW5nIHBsb3Qgb2JqZWN0cyB3aGVuIHdlIGZvcmdldCB3aGF0IHRoZXkgbG9vayBsaWtlLg0KDQoqVGhlIGNhdGNoIHdpdGggdGhpcyBhcHByb2FjaCBpcyB0aGUgcXVpY2sgYW5kIGRpcnR5IHByb3RvdHlwaW5nIGlzbid0IHF1aXRlIHNvIHF1aWNrLCBhbmQgdGhpcyBkb2N1bWVudCBlbmRzIHVwIHRha2luZyBGT1JFVkVSIHRvIGxvYWQuKiBNaWdodCBzd2l0Y2ggYmFjaz8gQnV0IGl0IHN1cmUgaXMgbmljZSB0byBhY3R1YWxseSBzZWUgd2hhdCBlYWNoIGZpZ3VyZSBJIG1hZGUgbG9va3MgbGlrZSwgZXNwZWNpYWxseSB3aGVuIHdlJ3JlIGxpa2VseSB0byBkcm9wIHRoaXMgZm9yIGV4dGVuZGVkIHBlcmlvZHMuDQoNClNldCB0aGUgZGF0ZSBmb3IgZXhhbXBsZXMNCmBgYHtyfQ0KYXZhaWxEYXlzIDwtIHN0X2dldF9kaW1lbnNpb25fdmFsdWVzKHdlcmFpQ3JvcFRlbXAsIHdoaWNoID0gJ3RpbWUnKQ0KZGF0ZXdhbnRlZCA8LSBhcy5jaGFyYWN0ZXIoYXZhaWxEYXlzWzE3XSkNCmBgYA0KDQoNCiMjIFN0YXRpYyB2ZXJzaW9ucyB3aXRoIGRyaXZlcnMgYW5kIG91dGNvbWVzDQpNYWtlIGEgc3RhdGljIHZlcnNpb24gdXNpbmcgdGhlIHRtYXAgZnVuY3Rpb25zDQpgYGB7cn0NCnN1cHByZXNzTWVzc2FnZXModG1hcF9tb2RlKCdwbG90JykpDQoNCmFsbGZ1bih0ZW1wT2JqID0gd2VyYWlDcm9wVGVtcCwgdGVtcEF0dCA9IDEsDQogICAgICAgICAgICAgICAgICAgaW51bk9iaiA9IHdlcmFpQ3JvcEludW4sIGludW5BdHQgPSAxLA0KICAgICAgICAgICAgICAgICAgIGdwcE9iaiA9IHdlcmFpQ3JvcFByZWRHUFAsIGdwcEF0dCA9IDEsDQogICAgICAgICAgICAgICAgICAgZXJPYmogPSB3ZXJhaUNyb3BQcmVkRVIsIGVyQXR0ID0gMSwNCiAgICAgICAgICAgICAgICAgICBkYXRld2FudGVkKQ0KDQpgYGANCkNsZWFuIHRoYXQgdXAganVzdCBhIGJpdCwgd2l0aCBhIGdyZXkgYmFja2dyb3VuZC4gcHJvYmFibHkgcHVsbCB0aGUgdGl0bGUgb2ZmIGJ1dCBpdCdzIG5pY2UgdG8gaGF2ZSBhcyByZWZlcmVuY2Ugd2hpbGUgaSdtIG1ha2luZyB0aGVzZQ0KDQpgYGB7cn0NCnRtX2dyaWRfc3RhdGljIDwtIHRtYXBfYXJyYW5nZSh0ZW1wZnVuKHdlcmFpQ3JvcFRlbXAsIDEsIGRhdGV3YW50ZWQpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRtX2xheW91dChiZy5jb2xvciA9ICJncmV5ODUiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnVuZnVuKHdlcmFpQ3JvcEludW4sIDEsIGRhdGV3YW50ZWQsIHRpdGxlZCA9IEZBTFNFKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bV9sYXlvdXQoYmcuY29sb3IgPSAiZ3JleTg1IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3BwZnVuKHdlcmFpQ3JvcFByZWRHUFAsIDEsIGRhdGV3YW50ZWQsIHRpdGxlZCA9IEZBTFNFKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bV9sYXlvdXQoYmcuY29sb3IgPSAiZ3JleTg1IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJmdW4od2VyYWlDcm9wUHJlZEVSLCAxLCBkYXRld2FudGVkLCB0aXRsZWQgPSBGQUxTRSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG1fbGF5b3V0KGJnLmNvbG9yID0gImdyZXk4NSIpKQ0KdG1fZ3JpZF9zdGF0aWMNCmBgYA0KDQpJIHRoaW5rIGZvciBjb21wbGV0ZW5lc3MgbGV0J3MgbWFrZSBhIGdncGxvdCB2ZXJzaW9uIHRvbyBhbmQgc2VlIHdoaWNoIGlzIGJldHRlci4NClRha2VzIG1vcmUgd29yaywgYnV0IGhhdmUgbW9yZSBjb250cm9sIChwcm9iYWJseSBqdXN0IGJlY2F1c2UgSSBzcGVhayBnZ3Bsb3QpDQoNCmBgYHtyfQ0KZ2dfZ3JpZF9zdGF0aWMgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UoDQogIHRlbXBmdW4od2VyYWlDcm9wVGVtcCwgMSwgZGF0ZXdhbnRlZCwgcGxvdFBrZyA9ICdnZ3Bsb3QnKSArIA0KICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gJ3RvcCcpKSArDQogICAgdGhlbWVfZ3JleShiYXNlX3NpemUgPSA4KSArIA0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLCANCiAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMywgJ2NtJykpLA0KICBpbnVuZnVuKHdlcmFpQ3JvcEludW4sIDEsIGRhdGV3YW50ZWQsIHRpdGxlZCA9IEZBTFNFLCBwbG90UGtnID0gJ2dncGxvdCcpICsgDQogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAndG9wJykpICsNCiAgICB0aGVtZV9ncmV5KGJhc2Vfc2l6ZSA9IDgpICsgDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsIA0KICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zLCAnY20nKSksDQogIGdwcGZ1bih3ZXJhaUNyb3BQcmVkR1BQLCAxLCBkYXRld2FudGVkLCB0aXRsZWQgPSBGQUxTRSwgcGxvdFBrZyA9ICdnZ3Bsb3QnKSArIA0KICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gJ3RvcCcpKSArDQogICAgdGhlbWVfZ3JleShiYXNlX3NpemUgPSA4KSArIA0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLCANCiAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMywgJ2NtJykpLA0KICBlcmZ1bih3ZXJhaUNyb3BQcmVkRVIsIDEsIGRhdGV3YW50ZWQsIHRpdGxlZCA9IEZBTFNFLCBwbG90UGtnID0gJ2dncGxvdCcpICsgDQogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAndG9wJykpICsNCiAgICB0aGVtZV9ncmV5KGJhc2Vfc2l6ZSA9IDgpICsgDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsIA0KICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zLCAnY20nKSksDQogIG5jb2wgPSAyLCBucm93ID0gMikNCnByaW50KGdnX2dyaWRfc3RhdGljKQ0KDQpgYGANCg0KQ29kZSBibG9jayB0byBwcmludCBhbmQgbWFrZSB0aG9zZSBpbnRvIGZpZ3MNCmBgYHtyfQ0KcGRmKGZpbGUucGF0aChzY3JpcHRPdXQsICdXZXJhaV90bS5wZGYnKSwgDQogICAgb25lZmlsZSA9IEZBTFNFLCBoZWlnaHQgPSAxMi8yLjU0LCB3aWR0aCA9IDE2LzIuNTQsIHVzZURpbmdiYXRzID0gRkFMU0UpDQpwcmludCh0bV9ncmlkX3N0YXRpYykNCmRldi5vZmYoKQ0KDQpwbmcoZmlsZS5wYXRoKHNjcmlwdE91dCwgJ1dlcmFpX3RtLnBuZycpLCANCiAgICBoZWlnaHQgPSAxMi8yLjU0LCB3aWR0aCA9IDE2LzIuNTQsIHVuaXRzID0gJ2luJywgcmVzID0gMzAwKQ0KcHJpbnQodG1fZ3JpZF9zdGF0aWMpDQpkZXYub2ZmKCkNCg0KIyBDYW4gSSBwcmludCB0aG9zZT8NCnBkZihmaWxlLnBhdGgoc2NyaXB0T3V0LCAnV2VyYWlfZ2cucGRmJyksIA0KICAgIG9uZWZpbGUgPSBGQUxTRSwgaGVpZ2h0ID0gMTIvMi41NCwgd2lkdGggPSAxNi8yLjU0LCB1c2VEaW5nYmF0cyA9IEZBTFNFKQ0KcHJpbnQoZ2dfZ3JpZF9zdGF0aWMpDQpkZXYub2ZmKCkNCg0KcG5nKGZpbGUucGF0aChzY3JpcHRPdXQsICdXZXJhaV9nZy5wbmcnKSwgDQogICAgaGVpZ2h0ID0gMTIvMi41NCwgd2lkdGggPSAxNi8yLjU0LCB1bml0cyA9ICdpbicsIHJlcyA9IDMwMCkNCnByaW50KGdnX2dyaWRfc3RhdGljKQ0KZGV2Lm9mZigpDQpgYGANCg0KIyMgVW5jZXJ0YWludHkNCg0KSSB0aGluayBub3cgdGhhdCBJIGhhdmUgdGhlIGZ1bmN0aW9ucywgdGhlcmUncyBhIHNsaWNrZXIgd2F5IHRvIGRvIHRoaXMsIGJ1dCBJIGRvbid0IHdhbnQgdG8gcmVpbnZlbnQgdGhlIHdoZWVsIGF0IHRoaXMgcG9pbnQuIE1pZ2h0IHdhbnQgdG8gdHVybiB0aGlzIGludG8gYSBmdW5jdGlvbj8NCg0KRVINCmBgYHtyfQ0KIyBFUg0KZXJfc2YgPC0gd2VyYWlDcm9wUHJlZEVSWzEsLF0gJT4lIA0KICBzdF9hc19zZigpICU+JSANCiAgc2VsZWN0KGFsbF9vZihkYXRld2FudGVkKSkgJT4lDQogIHJlbmFtZShFUiA9IDEpICU+JQ0KICBtdXRhdGUobG9nRVIgPSBsb2cxMCgxK0VSKSwgdHlwZSA9ICdlc3RpbWF0ZScpDQplcl9zZlBVIDwtIHdlcmFpQ3JvcFByZWRFUlsyLCxdICU+JSANCiAgc3RfYXNfc2YoKSAlPiUgDQogIHNlbGVjdChhbGxfb2YoZGF0ZXdhbnRlZCkpICU+JQ0KICByZW5hbWUoRVIgPSAxKSAlPiUNCiAgbXV0YXRlKGxvZ0VSID0gbG9nMTAoMStFUiksIHR5cGUgPSAndXBwZXInKQ0KZXJfc2ZQTCA8LSB3ZXJhaUNyb3BQcmVkRVJbMywsXSAlPiUgDQogIHN0X2FzX3NmKCkgJT4lIA0KICBzZWxlY3QoYWxsX29mKGRhdGV3YW50ZWQpKSAlPiUNCiAgcmVuYW1lKEVSID0gMSkgJT4lDQogIG11dGF0ZShsb2dFUiA9IGxvZzEwKDErRVIpLCB0eXBlID0gJ2xvd2VyJykNCg0KZXJfc2ZfTE1VIDwtIGJpbmRfcm93cyhlcl9zZiwgZXJfc2ZQVSwgZXJfc2ZQTCkgJT4lDQogIG11dGF0ZShuYW1lZFBJID0gaWZlbHNlKHR5cGUgPT0gJ2xvd2VyJywgIkxvd2VyIDk1JSBQSSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSh0eXBlID09ICdlc3RpbWF0ZScsICJFc3RpbWF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UodHlwZSA9PSAndXBwZXInLCAiVXBwZXIgOTUlIFBJIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1NDUkVXVVAnKSkpKQ0KDQplcmxhYmVsIDwtICdFUiAoa2cgMDIvZGF5KVxuYXQgbWF4IGV4dGVudCcNCg0KIyBDYW4gZ2V0IGF3YXkgd2l0aCB0aGlzIGJlY2F1c2UgcHJldHR5IHJhbmdlcyB3b3JrIG91dCBPSw0KZXJDb250cm9sIDwtIGVyc2V0dXAoZGF0YSA9IHdlcmFpQ3JvcFByZWRFUiwgYXR0bnVtID0gMSkNCg0KICBlcl9nZ191bmNlcnRhaW4gPC0gZ2dwbG90KCkgKw0KICAgIGdlb21fc2YoZGF0YSA9IGVyX3NmX0xNVSwgbWFwcGluZyA9IGFlcyhmaWxsID0gbG9nRVIpLCBjb2xvciA9IE5BKSArDQogICAgIyBnZW9tX3NmX2xhYmVsKGRhdGEgPSBsdGltTm9Ob3J0aCwgbWFwcGluZyA9IGFlcyhsYWJlbCA9IFZhbGxleU5hbWUpKSArDQogICAgY29vcmRfc2YoKSArDQogICAgIyBDbG9zZXN0IHRvIHRoZSB0bWFwDQogICAgc2NhbGVfZmlsbF9zdGVwc24oY29sb3JzID0gZXJDb250cm9sJGVycGFsLA0KICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGVyQ29udHJvbCRlcmJyZWFrc1syOmxlbmd0aChlckNvbnRyb2wkZXJicmVha3MpXSwNCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKG1pbihlckNvbnRyb2wkZXJicmVha3MpLCBtYXgoZXJDb250cm9sJGVyYnJlYWtzKSksDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gZXJDb250cm9sJGVybGFiZWxzLA0KICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gJ2xlZ2VuZCcsDQogICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IGVybGFiZWwpICsNCiAgICBmYWNldF9ncmlkKGZjdF9yZW9yZGVyKG5hbWVkUEksIC54ID0gbG9nRVIsIC5mdW4gPSBtYXgpfi4pICMgbG93ZXIsIGVzdGltYXQgYW5kIHVwcGVyIHNob3VsZCBhbHdheXMgZmFsbCBpbiB0aGF0IG9yZGVyIGZvciB0aGVpciBtYXhlcw0KDQplcl9nZ191bmNlcnRhaW4NCg0KYGBgDQoNCkdQUA0KYGBge3J9DQojIEdQUA0KIyBJJ20gc3VyZSB0aGdwcGUncyBhIHNsaWNrIHdheSB0byBzZWxlY3QgYWxsIHRocmVlIGF0dHJpYnV0ZXMgYW5kIGRvIHRoaXMgaW4gb25lDQojIGdvLCBidXQgSSBqdXN0IG5lZWQgdG8gZ2V0IHRoaXMgZG9uZQ0KZ3BwX3NmIDwtIHdlcmFpQ3JvcFByZWRHUFBbMSwsXSAlPiUgDQogIHN0X2FzX3NmKCkgJT4lIA0KICBzZWxlY3QoYWxsX29mKGRhdGV3YW50ZWQpKSAlPiUNCiAgcmVuYW1lKEdQUCA9IDEpICU+JQ0KICBtdXRhdGUobG9nR1BQID0gbG9nMTAoMStHUFApLCB0eXBlID0gJ2VzdGltYXRlJykNCmdwcF9zZlBVIDwtIHdlcmFpQ3JvcFByZWRHUFBbMiwsXSAlPiUgDQogIHN0X2FzX3NmKCkgJT4lIA0KICBzZWxlY3QoYWxsX29mKGRhdGV3YW50ZWQpKSAlPiUNCiAgcmVuYW1lKEdQUCA9IDEpICU+JQ0KICBtdXRhdGUobG9nR1BQID0gbG9nMTAoMStHUFApLCB0eXBlID0gJ3VwcGVyJykNCmdwcF9zZlBMIDwtIHdlcmFpQ3JvcFByZWRHUFBbMywsXSAlPiUgDQogIHN0X2FzX3NmKCkgJT4lIA0KICBzZWxlY3QoYWxsX29mKGRhdGV3YW50ZWQpKSAlPiUNCiAgcmVuYW1lKEdQUCA9IDEpICU+JQ0KICBtdXRhdGUobG9nR1BQID0gbG9nMTAoMStHUFApLCB0eXBlID0gJ2xvd2VyJykNCg0KZ3BwX3NmX0xNVSA8LSBiaW5kX3Jvd3MoZ3BwX3NmLCBncHBfc2ZQVSwgZ3BwX3NmUEwpICU+JQ0KICBtdXRhdGUobmFtZWRQSSA9IGlmZWxzZSh0eXBlID09ICdsb3dlcicsICJMb3dlciA5NSUgUEkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UodHlwZSA9PSAnZXN0aW1hdGUnLCAiRXN0aW1hdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHR5cGUgPT0gJ3VwcGVyJywgIlVwcGVyIDk1JSBQSSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdTQ1JFV1VQJykpKSkNCg0KZ3BwbGFiZWwgPC0gJ0dQUCAoa2cgMDIvZGF5KVxuYXQgbWF4IGV4dGVudCcNCg0KZ3BwQ29udHJvbCA8LSBncHBzZXR1cCh3ZXJhaUNyb3BQcmVkR1BQLCBhdHRudW0gID0gMSkNCg0KZ3BwX2dnX3VuY2VydGFpbiA8LSBnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IGdwcF9zZl9MTVUsIG1hcHBpbmcgPSBhZXMoZmlsbCA9IGxvZ0dQUCksIGNvbG9yID0gTkEpICsNCiAgIyBnZW9tX3NmX2xhYmVsKGRhdGEgPSBsdGltTm9Ob3J0aCwgbWFwcGluZyA9IGFlcyhsYWJlbCA9IFZhbGxleU5hbWUpKSArDQogIGNvb3JkX3NmKCkgKw0KICAjIENsb3Nlc3QgdG8gdGhlIHRtYXANCiAgc2NhbGVfZmlsbF9zdGVwc24oY29sb3JzID0gZ3BwQ29udHJvbCRncHBwYWwsDQogICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGdwcENvbnRyb2wkZ3BwYnJlYWtzWzI6bGVuZ3RoKGdwcENvbnRyb2wkZ3BwYnJlYWtzKV0sDQogICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMobWluKGdwcENvbnRyb2wkZ3BwYnJlYWtzKSwgbWF4KGdwcENvbnRyb2wkZ3BwYnJlYWtzKSksDQogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGdwcENvbnRyb2wkZ3BwbGFiZWxzLA0KICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICdsZWdlbmQnLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gZ3BwbGFiZWwpICsNCiAgZmFjZXRfZ3JpZChmY3RfcmVvcmRlcihuYW1lZFBJLCAueCA9IGxvZ0dQUCwgLmZ1biA9IG1heCl+LikgIyBsb3dlciwgZXN0aW1hdCBhbmQgdXBwZ3BwIHNob3VsZCBhbHdheXMgZmFsbCBpbiB0aGF0IG9yZGdwcCBmb3IgdGhlaXIgbWF4ZXMNCg0KZ3BwX2dnX3VuY2VydGFpbg0KYGBgDQoNCkNvbWJpbmUgdGhlIEVSIGFuZCBHUFAgYW5kIHNhdmUgYXMgZmlndXJlcw0KYGBge3J9DQpib3RoX3VuY2VydGFpbiA8LSBnZ3B1YnI6OmdnYXJyYW5nZShncHBfZ2dfdW5jZXJ0YWluICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gJ3RvcCcpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2dyZXkoYmFzZV9zaXplID0gOCkgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjMsICdjbScpKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcl9nZ191bmNlcnRhaW4gKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAndG9wJykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfZ3JleShiYXNlX3NpemUgPSA4KSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMywgJ2NtJykpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIsIG5yb3cgPSAxKQ0KYm90aF91bmNlcnRhaW4NCg0KIyBKdXN0IHByaW50IHRoZSBnZ3Bsb3RzDQojIENhbiBJIHByaW50IHRob3NlPw0KcGRmKGZpbGUucGF0aChzY3JpcHRPdXQsICdXZXJhaV91bmNlcnRhaW50eS5wZGYnKSwgDQogICAgb25lZmlsZSA9IEZBTFNFLCBoZWlnaHQgPSAxMi8yLjU0LCB3aWR0aCA9IDE2LzIuNTQsIHVzZURpbmdiYXRzID0gRkFMU0UpDQpwcmludChib3RoX3VuY2VydGFpbikNCmRldi5vZmYoKQ0KDQpwbmcoZmlsZS5wYXRoKHNjcmlwdE91dCwgJ1dlcmFpX3VuY2VydGFpbnR5LnBuZycpLCANCiAgICBoZWlnaHQgPSAxMi8yLjU0LCB3aWR0aCA9IDE2LzIuNTQsIHVuaXRzID0gJ2luJywgcmVzID0gMzAwKQ0KcHJpbnQoYm90aF91bmNlcnRhaW4pDQpkZXYub2ZmKCkNCmBgYA0KDQojIyBCYXIgY2hhcnRzDQptYWtlIGEgd2lkZSB2ZXJzaW9uIG9mIHRoZSBkYXRhIHNvIEkgY2FuIGhhdmUgbWlucyBhbmQgbWF4ZXMNCk9SLCBzaG91bGQgSSBkbyBhbGwgb2YgdGhlbSBhbmQgZmN0X29yZGVyIHRoZW0/DQoNCkpvaW5pbmcgc2VlbXMgc2FmZSwgYnV0IGdlb2dyYXBoaWMgam9pbnMgYXJlIGEgbWVzcy4gSXQgZG9lc24ndCB3b3JrIGF0IGFsbC4NCmJpbmRpbmcgY29scyBpcyBhY3R1YWxseSBzYWZlciBhbmQgd29ya3MNCiANCiMjIyBHUFANCg0KYGBge3J9DQpncHBfc2ZfTE1VX3dpZGUgPC0gYmluZF9jb2xzKGdwcF9zZlssLTRdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0X2Ryb3BfZ2VvbWV0cnkocmVuYW1lKGdwcF9zZlBVWywtYyg0KV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFVHUFAgPSBHUFAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyX2xvZ0dQUCA9IGxvZ0dQUCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RfZHJvcF9nZW9tZXRyeShyZW5hbWUoZ3BwX3NmUExbLC00XSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTEdQUCA9IEdQUCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlcl9sb2dHUFAgPSBsb2dHUFApKSkgJT4lDQogIG11dGF0ZSh3ZXRsYW5kSUQgPSByb3dfbnVtYmVyKCkpDQpgYGANCg0KTWF5YmUgZm9yIGEgc3Vic2V0IG9mIHdldGxhbmRzPw0KDQpgYGB7cn0NCiMgR3JhYiBzb21lIHNldCBvZiB3ZXRsYW5kcw0Kd2hpY2goZ3BwX3NmJGdlb21ldHJ5ID09IGdwcF9zZl9MTVUkZ2VvbWV0cnlbM10pDQpleGFtcGxlV2V0cyA8LSBjKDE6MTAwKQ0KYGBgDQoNCmBgYHtyfQ0KYmFyZ3BwIDwtIGdncGxvdChncHBfc2ZfTE1VX3dpZGVbZXhhbXBsZVdldHMsIF0sIA0KICAgICAgICAgICAgICAgICBhZXMoeCA9IHdldGxhbmRJRCwgeSA9IGxvZ0dQUCwgZmlsbCA9IGxvZ0dQUCkpICsNCiAgZ2VvbV9jb2woKSArICMgdGhlIGdlb21fYmFyIGVxdWl2YWxlbnQgd2hlbiBpdCdzIG5vdCBjb3VudGluZyBjYXNlcy4NCiAgZ2VvbV9lcnJvcmJhcihtYXBwaW5nID0gYWVzKHltaW4gPSBsb3dlcl9sb2dHUFAsIHltYXggPSB1cHBlcl9sb2dHUFApKSArDQogIHNjYWxlX2ZpbGxfc3RlcHNuKGNvbG9ycyA9IGdwcENvbnRyb2wkZ3BwcGFsLA0KICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBncHBDb250cm9sJGdwcGJyZWFrc1syOmxlbmd0aChncHBDb250cm9sJGdwcGJyZWFrcyldLA0KICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKG1pbihncHBDb250cm9sJGdwcGJyZWFrcyksIG1heChncHBDb250cm9sJGdwcGJyZWFrcykpLA0KICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBncHBDb250cm9sJGdwcGxhYmVscywNCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSAnbGVnZW5kJywNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IGdwcGxhYmVsKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBncHBDb250cm9sJGdwcGJyZWFrc1syOmxlbmd0aChncHBDb250cm9sJGdwcGJyZWFrcyldLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gcm91bmQoMTBeKGdwcENvbnRyb2wkZ3BwYnJlYWtzWzI6bGVuZ3RoKGdwcENvbnRyb2wkZ3BwYnJlYWtzKV0pKSkgKw0KICBsYWJzKHggPSAnV2V0bGFuZCcsIHkgPSBncHBsYWJlbCkNCmJhcmdwcA0KDQpgYGANCg0KIEkgYXNzdW1lIGl0IGlzIGEgbWVzIHRvIGp1c3QgdGhyb3cgdGhlbSBhbGwgb24NCiBhY3R1YWxseSwgd2l0aCBhIGZhaXIgYW1vdW50IG9mIG1vbmtleWluZyB3aXRoIHRoZSBsb29rLCB0aGF0J3MgT0sNCiANCmBgYHtyfQ0KYmFyZ3BwYWxsIDwtIGdncGxvdChncHBfc2ZfTE1VX3dpZGUsIA0KICAgICAgICAgICAgICAgICBhZXMoeCA9IGZjdF9yZW9yZGVyKGFzLmZhY3Rvcih3ZXRsYW5kSUQpLCBsb2dHUFAsIC5kZXNjID0gVFJVRSksIHkgPSBsb2dHUFAsIGZpbGwgPSBsb2dHUFApKSArDQogIGdlb21fY29sKCkgKyAjIHRoZSBnZW9tX2JhciBlcXVpdmFsZW50IHdoZW4gaXQncyBub3QgY291bnRpbmcgY2FzZXMuDQogIGdlb21fbGluZXJhbmdlKG1hcHBpbmcgPSBhZXMoeW1pbiA9IGxvd2VyX2xvZ0dQUCwgeW1heCA9IHVwcGVyX2xvZ0dQUCksDQogICAgICAgICAgICAgICAgIGNvbG9yID0gJ2dyZXk1MCcsIGFscGhhID0gMC4yKSArDQogIHNjYWxlX2ZpbGxfc3RlcHNuKGNvbG9ycyA9IGdwcENvbnRyb2wkZ3BwcGFsLA0KICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBncHBDb250cm9sJGdwcGJyZWFrc1syOmxlbmd0aChncHBDb250cm9sJGdwcGJyZWFrcyldLA0KICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKG1pbihncHBDb250cm9sJGdwcGJyZWFrcyksIG1heChncHBDb250cm9sJGdwcGJyZWFrcykpLA0KICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBncHBDb250cm9sJGdwcGxhYmVscywNCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSAnbGVnZW5kJywNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IGdwcGxhYmVsKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBncHBDb250cm9sJGdwcGJyZWFrc1syOmxlbmd0aChncHBDb250cm9sJGdwcGJyZWFrcyldLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gcm91bmQoMTBeKGdwcENvbnRyb2wkZ3BwYnJlYWtzWzI6bGVuZ3RoKGdwcENvbnRyb2wkZ3BwYnJlYWtzKV0pKSkgKw0KICBsYWJzKHggPSAnV2V0bGFuZCcsIHkgPSBncHBsYWJlbCkNCmJhcmdwcGFsbA0KYGBgDQogDQpJIGFjdHVhbGx5IGxpa2UgdGhhdCB0aGF0IGVuY29tcGFzc2VzIGFuIGFyZWEgdGhhdCBpbnRlZ3JhdGVzIHRvIHRvdGFsIHByb2R1Y3Rpb24gYWNyb3NzIHRoZSBXZXJhaQ0KDQpJIGNhbiBkbyBwb2ludHMgYXMgYmVsb3csIGJ1dCB0aGUgaW50ZWdyYXRpb24gaW1wbGllZCBhYm92ZSBpcyBuaWNlDQoNCmBgYHtyfQ0KYmFyZ3BwYWxscG9pbnQgPC0gZ2dwbG90KGdwcF9zZl9MTVVfd2lkZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBmY3RfcmVvcmRlcihhcy5mYWN0b3Iod2V0bGFuZElEKSwgbG9nR1BQKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dHUFAsIGNvbG9yID0gbG9nR1BQKSkgKw0KICBnZW9tX2xpbmVyYW5nZShtYXBwaW5nID0gYWVzKHltaW4gPSBsb3dlcl9sb2dHUFAsIHltYXggPSB1cHBlcl9sb2dHUFApLCBjb2xvciA9ICdncmV5NTAnKSArDQogIGdlb21fcG9pbnQoKSArICMgdGhlIGdlb21fYmFyIGVxdWl2YWxlbnQgd2hlbiBpdCdzIG5vdCBjb3VudGluZyBjYXNlcy4NCiAgc2NhbGVfY29sb3Jfc3RlcHNuKGNvbG9ycyA9IGdwcENvbnRyb2wkZ3BwcGFsLA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gZ3BwQ29udHJvbCRncHBicmVha3NbMjpsZW5ndGgoZ3BwQ29udHJvbCRncHBicmVha3MpXSwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMobWluKGdwcENvbnRyb2wkZ3BwYnJlYWtzKSwgbWF4KGdwcENvbnRyb2wkZ3BwYnJlYWtzKSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBncHBDb250cm9sJGdwcGxhYmVscywNCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gJ2xlZ2VuZCcsDQogICAgICAgICAgICAgICAgICAgICBuYW1lID0gZ3BwbGFiZWwpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGdwcENvbnRyb2wkZ3BwYnJlYWtzWzI6bGVuZ3RoKGdwcENvbnRyb2wkZ3BwYnJlYWtzKV0sDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSByb3VuZCgxMF4oZ3BwQ29udHJvbCRncHBicmVha3NbMjpsZW5ndGgoZ3BwQ29udHJvbCRncHBicmVha3MpXSkpKSArDQogIGxhYnMoeCA9ICdXZXRsYW5kJywgeSA9IGdwcGxhYmVsKQ0KYmFyZ3BwYWxscG9pbnQNCmBgYA0KDQojIyMgRVINCg0KU2V0dXAgYmxvY2suIEFnYWluLCB0aGlzIGNvdWxkIGJlIHNvcnRlZCB3aXRoIGEgZnVuY3Rpb24sIGJ1dCByaWdodCBub3cganVzdCBjb3B5LXBhc3RpbmcNCg0KYGBge3J9DQplcmxhYmVsIDwtICdHUFAgKGtnIDAyL2RheSlcbmF0IG1heCBleHRlbnQnDQoNCmVyX3NmX0xNVV93aWRlIDwtIGJpbmRfY29scyhlcl9zZlssLTRdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RfZHJvcF9nZW9tZXRyeShyZW5hbWUoZXJfc2ZQVVssLWMoNCldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVUVSID0gRVIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlcl9sb2dFUiA9IGxvZ0VSKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0X2Ryb3BfZ2VvbWV0cnkocmVuYW1lKGVyX3NmUExbLC00XSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExFUiA9IEVSLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlcl9sb2dFUiA9IGxvZ0VSKSkpICU+JQ0KICBtdXRhdGUod2V0bGFuZElEID0gcm93X251bWJlcigpKQ0KYGBgDQoNCkJhcnBsb3QNCmBgYHtyfQ0KYmFyZXJhbGwgPC0gZ2dwbG90KGVyX3NmX0xNVV93aWRlLCANCiAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBmY3RfcmVvcmRlcihhcy5mYWN0b3Iod2V0bGFuZElEKSwgbG9nRVIsIC5kZXNjID0gVFJVRSksIHkgPSBsb2dFUiwgZmlsbCA9IGxvZ0VSKSkgKw0KICBnZW9tX2NvbCgpICsgIyB0aGUgZ2VvbV9iYXIgZXF1aXZhbGVudCB3aGVuIGl0J3Mgbm90IGNvdW50aW5nIGNhc2VzLg0KICBnZW9tX2xpbmVyYW5nZShtYXBwaW5nID0gYWVzKHltaW4gPSBsb3dlcl9sb2dFUiwgeW1heCA9IHVwcGVyX2xvZ0VSKSwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSAnZ3JleTUwJywgYWxwaGEgPSAwLjIpICsNCiAgc2NhbGVfZmlsbF9zdGVwc24oY29sb3JzID0gZXJDb250cm9sJGVycGFsLA0KICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBlckNvbnRyb2wkZXJicmVha3NbMjpsZW5ndGgoZXJDb250cm9sJGVyYnJlYWtzKV0sDQogICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMobWluKGVyQ29udHJvbCRlcmJyZWFrcyksIG1heChlckNvbnRyb2wkZXJicmVha3MpKSwNCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gZXJDb250cm9sJGVybGFiZWxzLA0KICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICdsZWdlbmQnLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gZXJsYWJlbCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gZXJDb250cm9sJGVyYnJlYWtzWzI6bGVuZ3RoKGVyQ29udHJvbCRlcmJyZWFrcyldLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gcm91bmQoMTBeKGVyQ29udHJvbCRlcmJyZWFrc1syOmxlbmd0aChlckNvbnRyb2wkZXJicmVha3MpXSkpKSArDQogIGxhYnMoeCA9ICdXZXRsYW5kJywgeSA9IGVybGFiZWwpDQpiYXJlcmFsbA0KYGBgDQoNCiMjIyBCb3RoIHRvZ2V0aGVyLCB3aXRoIEdQUCB1cCBhbmQgRVIgZG93bg0KDQpTZXR1cA0KYGBge3J9DQojIENhbiBJIG1ha2Ugb25lIHdpdGggdGhlbSBib3RoIHRoZXJlIGdvaW5nIG9wcG9zaXRlIGRpcmVjdGlvbj8NCmJvdGhfc2ZfTE1VX3dpZGUgPC0gYmluZF9jb2xzKG11dGF0ZShncHBfc2ZfTE1VX3dpZGUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShzdF9kcm9wX2dlb21ldHJ5KGVyX3NmX0xNVV93aWRlWywtYyg4KV0pKSkNCg0KIyBOZWVkIG5ldyBsYWJlbHMgYW5kIGJyZWFrcy4gQ291bGQgY29iYmxlLCBidXQgZ2V0dGluZyBjb25mdXNpbmcgYW5kIG1pc2FsaWduZWQNCiMgYm90aGJyZWFrc19sb2cgPC0gYygtcmV2KGVyYnJlYWtzX2xvZ1syOmxlbmd0aChlcmJyZWFrc19sb2cpXSksIGdwcGJyZWFrc19sb2cpDQogDQojICMgYW5kIHRob3NlIGJyZWFrcyBtaWdodCBub3QgcXVpdGUgeWllbGQgMTAsIHNvIG1heGltaXNlIHRoZSBwYWxldHRlIGRpZmZlcmVuY2VzDQojIGVycGFsX2xvZyA8LSBzZXF1ZW50aWFsX2hjbChsZW5ndGgoZXJicmVha3NfbG9nKS0xLCBwYWxldHRlID0gJ1B1cnBsZXMnLCByZXYgPSBUUlVFKQ0KIyBJIHRoaW5rIGhlcmUgSSB3YW50IGNvbnRpbnVvdXMgY29sb3JzLiBidXQgbWF5YmUgc3RpbGwgYSBicm9rZW4gdXAgbGVnZW5kPw0KDQojIGhhdmUgdG8gZG8gdGhlIG5lZ2F0aXZlcyBiZWZvcmUgZGVsb2dnaW5nDQojIGJvdGhsYWJlbHNfbG9nIDwtIGMoLTEwXnJldihlcmJyZWFrc19sb2cpLCAxMF5ncHBicmVha3NfbG9nKQ0KIyANCiMgYm90aGxhYmVsc19sb2cgPC0gZm9ybWF0KGJvdGhsYWJlbHNfbG9nLCBiaWcubWFyaz0iLCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAjIHNjaWVudGlmaWM9RkFMU0UsIHRyaW0gPSBUUlVFLCBkaWdpdHMgPSAwKQ0KDQojIFRoaXMgaXMgcmVhbGx5IGdldHRpbmcgY29tcGxleC4gV2h5IGRvbid0IEkganVzdCB1c2UgMCwxLDEwLDEwMCwxMDAwLDEwMDAwPw0KIyBUaGV5J3ZlIGJvdGggYmVlbiBzaGlmdGVkIGJ5IDEgdG8gbG9nLCBzbw0KIyBUaGlzIGlzIGp1c3QgdXNlZCB0byBnZXQgdGhlIGxhYmVscywgdGhlIGFjdHVhbCBsb2ctc2NhbGUgaXMgcGxvdHRlZCBhbmQgc28gdGhlIHplcm9zIGFyZSBkb25lIGNvcnJlY3RseQ0KYm90aGJyZWFrc19sb2cgPC0gYygtMTBeKDQ6MCksIDEwXigxOjQpKQ0KYm90aGJyZWFrc19sb2dbNV0gPC0gMCAjIEJlY2F1c2UgYm90aCB3ZXJlIHNoaWZ0ZWQgc28gMSA9IDANCmJvdGhsYWJlbHNfbG9nIDwtIGFzLmNoYXJhY3Rlcihib3RoYnJlYWtzX2xvZykNCg0KDQojIGVyc3RhcnQgPC0gZXJsYWJlbHNfbG9nWzE6KGxlbmd0aChlcmxhYmVsc19sb2cpLTEpXQ0KIyBlcnN0YXJ0WzFdIDwtICIwIiAjIGluc3RlYWQgb2YgMQ0KIyBib3RobGFiZWxzX2xvZyA8LSBwYXN0ZTAoZXJzdGFydCwgJyB0byAnLCBlcmxhYmVsc19sb2dbMjpsZW5ndGgoZXJsYWJlbHNfbG9nKV0pDQojIGVybGFiZWxzX2xvZw0KDQojIEFBQUEgdHJ5IHRvIGdldCBzb21lIGxhYmxlcyBmb3IgdGhlIHguIEkgSlVTVCBXQU5UIElUIFRPIEhBVkUgVEhFIE5VTUJFUiBCVVQgSVQgV09OIlQgRE8gSVQNCnJlb3JkeCA8LSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoYm90aF9zZl9MTVVfd2lkZSR3ZXRsYW5kSUQpLCANCiAgICAgICAgICAgICAgICAgICAgICBib3RoX3NmX0xNVV93aWRlJGxvZ0dQUCwgLmRlc2MgPSBUUlVFKQ0KIyBJJ20gY29uZnVzZWQuIHRoYXQgZGlkbid0IHdvcmsuIHRoaXMgaXMgYW5veXV0aW5nDQpgYGANCg0KVHJ5IGEgcGxvdA0KDQpgYGB7cn0NCmJhcmJvdGggPC0gZ2dwbG90KGJvdGhfc2ZfTE1VX3dpZGUpICsNCiAgZ2VvbV9jb2wobWFwcGluZyA9IGFlcyh4ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKHdldGxhbmRJRCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dFUiwgLmRlc2MgPSBUUlVFKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IC1sb2dFUiwgZmlsbCA9IC1sb2dFUikpICsgIyB0aGUgZ2VvbV9iYXIgZXF1aXZhbGVudCB3aGVuIGl0J3Mgbm90IGNvdW50aW5nIGNhc2VzLg0KICBnZW9tX2xpbmVyYW5nZShtYXBwaW5nID0gYWVzKHggPSBmY3RfcmVvcmRlcihhcy5mYWN0b3Iod2V0bGFuZElEKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0VSLCAuZGVzYyA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSAtbG93ZXJfbG9nRVIsIHltYXggPSAtdXBwZXJfbG9nRVIpLA0KICAgICAgICAgICAgICAgICBjb2xvciA9ICdncmV5NTAnLCBhbHBoYSA9IDAuMikgKw0KICAjIHNjYWxlX2ZpbGxfc3RlcHNuKGNvbG9ycyA9IGVycGFsX2xvZywNCiAgIyAgICAgICAgICAgICAgICAgICBicmVha3MgPSBlcmJyZWFrc19sb2dbMjpsZW5ndGgoZXJicmVha3NfbG9nKV0sDQogICMgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhtaW4oZXJicmVha3NfbG9nKSwgbWF4KGVyYnJlYWtzX2xvZykpLA0KICAjICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGVybGFiZWxzX2xvZywNCiAgIyAgICAgICAgICAgICAgICAgICBndWlkZSA9ICdsZWdlbmQnLA0KICAjICAgICAgICAgICAgICAgICAgIG5hbWUgPSBlcmxhYmVsKSArDQogDQogICMgc2NhbGVfZmlsbF9zdGVwc24oY29sb3JzID0gYyhyZXYoZXJwYWxfbG9nKSwgZ3BwcGFsX2xvZyksDQogICMgICAgICAgICAgICBicmVha3MgPSBjKC1yZXYoZXJicmVha3NfbG9nWzI6bGVuZ3RoKGVyYnJlYWtzX2xvZyldKSwgMCwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgZ3BwYnJlYWtzX2xvZ1syOmxlbmd0aChncHBicmVha3NfbG9nKV0pLA0KICAjICAgICAgICAgICAgbGltaXRzID0gYyhtaW4oLWVyYnJlYWtzX2xvZyksIG1heChncHBicmVha3NfbG9nKSksDQogICMgICAgICAgICAgICAjIGxhYmVscyA9IGMoZXJsYWJlbHNfbG9nLCBncHBsYWJlbHNfbG9nKSwNCiAgIyAgICAgICAgICAgIGd1aWRlID0gJ2xlZ2VuZCcsDQogICMgICAgICAgICAgICBuYW1lID0gJ2tnIE8yXG5hdCBtYXggZXh0ZW50JykgKw0KICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBmY3RfcmVvcmRlcihhcy5mYWN0b3Iod2V0bGFuZElEKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0dQUCwgLmRlc2MgPSBUUlVFKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ0dQUCwgZmlsbCA9IGxvZ0dQUCkpICsNCiAgZ2VvbV9saW5lcmFuZ2UobWFwcGluZyA9IGFlcyh4ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKHdldGxhbmRJRCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dHUFAsIC5kZXNjID0gVFJVRSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IGxvd2VyX2xvZ0dQUCwgeW1heCA9IHVwcGVyX2xvZ0dQUCksDQogICAgICAgICAgICAgICAgIGNvbG9yID0gJ2dyZXk1MCcsIGFscGhhID0gMC4yKSArDQogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSBmY3RfcmVvcmRlcihhcy5mYWN0b3Iod2V0bGFuZElEKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nR1BQLCAuZGVzYyA9IFRSVUUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dHUFAtbG9nRVIsIGdyb3VwID0gTkEpKSArDQogIA0KICAjIFRoaXMgcGFsZXR0ZSBpcyB2ZXJ5IHNsaWdodGx5IGRpZmZlcmVudCBiZWNhdXNlIGl0J3Mgbm90IGJpbm5lZCBhbmQgR1BQIGFib3ZlIHVzZXMgRW1lcmFsZCBpbnN0ZWFkIG9mIGdyZWVuLCBidXQgaXQncyBzdXJlIGNsb3NlIGFuZCB3YXkgZWFzaWVyDQogIHNjYWxlX2ZpbGxfY29udGludW91c19kaXZlcmdpbmcocGFsZXR0ZSA9ICJQdXJwbGUtR3JlZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoLTQsIDQpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSAtNDo0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGJvdGhsYWJlbHNfbG9nKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC00LCA0KSwNCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IC00OjQsDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBib3RobGFiZWxzX2xvZykgKw0KICAjIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKC1lcmJyZWFrc19sb2dbMjpsZW5ndGgoZXJicmVha3NfbG9nKV0sIA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwcGJyZWFrc19sb2dbMjpsZW5ndGgoZ3BwYnJlYWtzX2xvZyldKSwNCiAgIyAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygtcm91bmQoMTBeKGVyYnJlYWtzX2xvZ1syOmxlbmd0aChlcmJyZWFrc19sb2cpXSkpLCANCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3VuZCgxMF4oZ3BwYnJlYWtzX2xvZ1syOmxlbmd0aChncHBicmVha3NfbG9nKV0pKSkpICsNCiAgbGFicyh4ID0gJ1dldGxhbmQgKG9yZGVyZWQgYnkgR1BQKScsIHkgPSAna2cgTzInLCBmaWxsID0gJ2tnIE8yJykgKw0KICAjIGFyZ2ggZG9lc24ndCB3b3JrIGJlY2F1c2UgaGFzIGJlZW4gcmVvcmRlcmVkDQogICMgc2NhbGVfeF9kaXNjcmV0ZShicmVha3MgPSBhcy5jaGFyYWN0ZXIoYygxLCAyNTAsIDUwMCwgNzUwLCAxMDAwKSkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjc1LCAwLjU0KSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuNzUsIDAuNTUpKQ0KYmFyYm90aA0KYGBgDQoNClRoZSBpbmFiaWxpdHkgdG8gbGFiZWwgeCBpbiBhIHJlYXNvbmFibGUgd2F5IGlzIGluZnVyaWF0aW5nLiBDYW4gSSBkbyBpdCBkaWZmZXJlbnRseT8gVHJ5IG1ha2luZyBhIGxhYmVsbGVkIGRhdGFzZXQgdGhhdCdzIGFycmFuZ2VkIGhvdyBJIHdhcyBkb2luZyBmY3RfcmVvcmRlci4NCg0KYGBge3J9DQpib3RoX3NmX0xNVV93aWRlMiA8LSBib3RoX3NmX0xNVV93aWRlICU+JSANCiAgYXJyYW5nZShkZXNjKGxvZ0dQUCkpICU+JSANCiAgbXV0YXRlKEdQUHJhbmsgPSByb3dfbnVtYmVyKCkpDQpgYGANCg0KTWFrZSB0aGUgcGxvdC4gSW50ZXJlc3RpbmcgdGhhdCB0aGUgbm90ZWJvb2sgcGxvdHRlciBkb2VzIGEgd29yc2Ugam9iIHRoYW4gdGhlIHBsb3RzIHBhbmVsIGZvciBhIHNjcmlwdC4gVGhlIGZ1bm55IGdhcHMgYXJlbid0IHJlYWxseSB0aGVyZS0gdG8gc2VlLCBydW4gYmFyYm90aCBpbiB0aGUgY29uc29sZS4NCg0KYGBge3J9DQpiYXJib3RoIDwtIGdncGxvdChib3RoX3NmX0xNVV93aWRlMikgKw0KICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBHUFByYW5rLCANCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLWxvZ0VSLCBmaWxsID0gLWxvZ0VSKSkgKyAjIHRoZSBnZW9tX2JhciBlcXVpdmFsZW50IHdoZW4gaXQncyBub3QgY291bnRpbmcgY2FzZXMuDQogIGdlb21fbGluZXJhbmdlKG1hcHBpbmcgPSBhZXMoeCA9IEdQUHJhbmssDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbiA9IC1sb3dlcl9sb2dFUiwgeW1heCA9IC11cHBlcl9sb2dFUiksDQogICAgICAgICAgICAgICAgIGNvbG9yID0gJ2dyZXk1MCcsIGFscGhhID0gMC4yKSArDQoNCmdlb21fY29sKG1hcHBpbmcgPSBhZXMoeCA9IEdQUHJhbmssIA0KICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nR1BQLCBmaWxsID0gbG9nR1BQKSkgKw0KICBnZW9tX2xpbmVyYW5nZShtYXBwaW5nID0gYWVzKHggPSBHUFByYW5rLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSBsb3dlcl9sb2dHUFAsIHltYXggPSB1cHBlcl9sb2dHUFApLA0KICAgICAgICAgICAgICAgICBjb2xvciA9ICdncmV5NTAnLCBhbHBoYSA9IDAuMikgKw0KICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0gR1BQcmFuaywgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dHUFAtbG9nRVIsIGdyb3VwID0gTkEpKSArDQogIA0KICAjIFRoaXMgcGFsZXR0ZSBpcyB2ZXJ5IHNsaWdodGx5IGRpZmZlcmVudCBiZWNhdXNlIGl0J3Mgbm90IGJpbm5lZCBhbmQgR1BQIGFib3ZlIHVzZXMgRW1lcmFsZCBpbnN0ZWFkIG9mIGdyZWVuLCBidXQgaXQncyBzdXJlIGNsb3NlIGFuZCB3YXkgZWFzaWVyDQogIHNjYWxlX2ZpbGxfY29udGludW91c19kaXZlcmdpbmcocGFsZXR0ZSA9ICJQdXJwbGUtR3JlZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoLTQsIDQpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSAtNDo0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGJvdGhsYWJlbHNfbG9nKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC00LCA0KSwNCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IC00OjQsDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBib3RobGFiZWxzX2xvZykgKw0KICBsYWJzKHggPSAnV2V0bGFuZCAob3JkZXJlZCBieSBHUFApJywgeSA9ICdrZyBPMicsIGZpbGwgPSAna2cgTzInKSArDQogICMgc2NhbGVfeF9kaXNjcmV0ZShicmVha3MgPSBjKDEsIDI1MCwgNTAwLCA3NTAsIDEwMDApKSArDQogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjc1LCAwLjUzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpDQpiYXJib3RoDQpgYGANCg0KU2F2ZSB0aGF0IGFzIGEgZmlndXJlDQoNCmBgYHtyfQ0KcGRmKGZpbGUucGF0aChzY3JpcHRPdXQsICdXZXJhaV9taXJyb3JncmFtLnBkZicpLCANCiAgICBvbmVmaWxlID0gRkFMU0UsIGhlaWdodCA9IDgvMi41NCwgd2lkdGggPSAxMi8yLjU0LCB1c2VEaW5nYmF0cyA9IEZBTFNFKQ0KcHJpbnQoYmFyYm90aCkNCmRldi5vZmYoKQ0KDQpwbmcoZmlsZS5wYXRoKHNjcmlwdE91dCwgJ1dlcmFpX21pcnJvcmdyYW0ucG5nJyksIA0KICAgIGhlaWdodCA9IDgvMi41NCwgd2lkdGggPSAxMi8yLjU0LCB1bml0cyA9ICdpbicsIHJlcyA9IDMwMCkNCnByaW50KGJhcmJvdGgpDQpkZXYub2ZmKCkNCmBgYA0KDQoNCldoYXQgYWJvdXQgRGFycmVuJ3MgZmluZ2VycHJpbnRzPyBUaGV5IHdvdWxkIG1heWJlIHRha2UgdGhlIEdQUCBhbmQgRVIgYW5kDQptYWtlIGEgZGVuc2l0eSB3aXRoIHRoZW0/IE9VdCBvZiB3aGF0PyBUaGUgd2V0bGFuZHM/IENvdWxkIHdvcmsuIFdvdWxkIG5lZWQgdG8NCnNvcnQgb3V0IHRoZSB3ZWlnaHRpbmcgYnkgdm9sdW1lLiBpdCdzIGFscmVhZHkgaW4gdGhlcmUsIGJ1dCB0aGF0IG1lYW5zIGl0DQp3aWxsIGdpdmUgZWFjaCBsb2NhdGlvbiB0aGUgc2FtZSB3ZWlnaHQuIEkgdGhpbmsgYSBiZXR0ZXIgdGhpbmcgZm9yIHRoZQ0KZmluZ2VycHJpbnRzIHdvdWxkIGJlIHRvIHJlbW92ZSBpdCwgYW5kIHRoZW4gZ2l2ZSBlYWNoIHdldGxhbmQgaXRzIHByZWRpY3RlZA0KcGVyIGxpdGVyIHJhdGUgYW5kIHdlaWdodCBieSB2b2x1bWUgSUUgdXNlIHRoZSBzdHJhaWdodCBwcmVkaWN0aW9ucyBhbmQgdGhlbg0Kd2VpZ2h0IGJ5IGludW5kYXRvbiBTaG91bGQgYmUgc3RyYWlnaHRmb3J3YXJkLCBidXQgbGlrZWx5IHdvbid0IGJlIA0KDQpXb3VsZCBiZSBhIHJlYWxseSBjb29sIHdheSB0byBsb29rIGF0IHNjZW5hcmlvcy4gZXNwZWNpYWxseSBpZiBJIGNhbiBkbyBpdA0KZm9yIHdob2xlIGNhdGNobWVudHMNCg0KQlVULCBiZWNhdXNlIEdQUCBhbmQgRVIgYXJlIGJvdGggbGluZWFyIGZpdHMgb2YgdGVtcCwgdGhleSB3aWxsIGV4YWN0bHkNCnByZWRpY3QgZWFjaCBvdGhlciBhY2NvcmRpbmcgdG8gYSBsaW5lYXIgcmVsYXRpb25zaGlwLCBhbmQgc28gdGhlcmUgd29uJ3QgYmUNCmFueSAyLWQgdmFyaWF0aW9uIGFuZCBhbGwgdGhlIHBvaW50cyB3aWxsIGZhbGwgb24gYSBsaW5lLiBJRSBmb3IgYSBnaXZlbiBHUFANCnRoZXJlIHdpbGwgb25seSBiZSBvbmUgRVIsIGFuZCBzbyB0aGUgZmluZ2VycHJpbnQgd2lsbCBiZSBhIGxpbmUuIENvb2wgaWRlYSwNCmJ1dCB3ZSdkIG5lZWQgbW9yZSBpbmZvIGFib3V0IHRoZWlyIHZhcmlhbmNlIHJlbGF0aXZlIHRvIGVhY2ggb3RoZXINCg0KIyMgQW5udWFsIHJlcG9ydGluZw0KDQpXaGF0IGFib3V0IG1ha2luZyBzb21lIGV4YW1wbGVzIHRvIGlsbHVzdHJhdGUgYW5udWFsIChvciBhcmJpdHJhcnkgdGltZSBwZXJpb2QpIHJlcG9ydGluZz8NCg0KRmlyc3QsIGVzdGFibGlzaCB0aGUgdGltZSBwZXJpb2RzIGFuZCBkbyB0aGUgYWdncmVnYXRpb25zIGFuZCBvdGhlciBkYXRhIG9yZ2FuaXNhdGlvbg0KDQpgYGB7cn0NCmludGVyRGF0ZXMgPC0gYXMuUE9TSVhjdChjKCIyMDE0LTA2LTMwIiwgIjIwMTUtMDYtMzAiLCAiMjAxNi0wNi0zMCIsICIyMDE3LTA2LTMwIiwgIjIwMTgtMDYtMzAiLCAiMjAxOS0wNi0zMCIpKQ0KDQp0ZW1wYW5udWFsIDwtIHRlbXBhZ2dyZWdhdGUod2VyYWlDcm9wVGVtcCwgYnlfdCA9IGFzLkRhdGUoaW50ZXJEYXRlcyksIEZVTiA9IG1lYW4sIG5hLnJtID0gVFJVRSkNCmludW5hbm51YWwgPC0gdGVtcGFnZ3JlZ2F0ZSh3ZXJhaUNyb3BJbnVuLCBieV90ID0gYXMuRGF0ZShpbnRlckRhdGVzKSwgRlVOID0gc3VtLCBuYS5ybSA9IFRSVUUpDQpncHBhbm51YWwgPC0gdGVtcGFnZ3JlZ2F0ZSh3ZXJhaUNyb3BQcmVkR1BQWzEsLF0sIGJ5X3QgPSBhcy5EYXRlKGludGVyRGF0ZXMpLCBGVU4gPSBzdW0sIG5hLnJtID0gVFJVRSkNCmVyYW5udWFsIDwtIHRlbXBhZ2dyZWdhdGUod2VyYWlDcm9wUHJlZEVSWzEsLF0sIGJ5X3QgPSBhcy5EYXRlKGludGVyRGF0ZXMpLCBGVU4gPSBzdW0sIG5hLnJtID0gVFJVRSkNCg0KIyBEYXRhIG9yZ2FuaXNhdGlvbg0KIyBBSEhIIHRoZSBmbG9wcGVkIGRpbXMNCmlmIChhdHRyaWJ1dGVzKHN0X2RpbWVuc2lvbnMoZ3BwYW5udWFsKSkkbmFtZVsxXSAhPSAnZ2VvbWV0cnknKSB7DQogIGdwcGFubnVhbCA8LSBhcGVybShncHBhbm51YWwsIGMoMiwxKSkNCn0NCmlmIChhdHRyaWJ1dGVzKHN0X2RpbWVuc2lvbnMoZXJhbm51YWwpKSRuYW1lWzFdICE9ICdnZW9tZXRyeScpIHsNCiAgZXJhbm51YWwgPC0gYXBlcm0oZXJhbm51YWwsIGMoMiwxKSkNCn0NCg0KIyBHUFANCmdwcFllYXJfc2YgPC0gZ3BwYW5udWFsICU+JSANCiAgc3RfYXNfc2YoKSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gLWdlb21ldHJ5LCBuYW1lc190byA9ICdXYXRlclllYXInLCB2YWx1ZXNfdG8gPSAnR1BQJykgJT4lDQogIG11dGF0ZShsb2dHUFAgPSAgbG9nMTAoMStHUFApKSAlPiUNCiAgc3RfYXNfc2YoKSAjIFJFQUxMWT8/Pw0KZ3BwWWVhcl9zZg0KDQptYXgoZ3BwWWVhcl9zZiRsb2dHUFApICMgaXMgd2l0aGluIA0KZ3BwQ29udHJvbCRncHBicmVha3MNCg0KIyBFUg0KZXJZZWFyX3NmIDwtIGVyYW5udWFsICU+JSANCiAgc3RfYXNfc2YoKSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gLWdlb21ldHJ5LCBuYW1lc190byA9ICdXYXRlclllYXInLCB2YWx1ZXNfdG8gPSAnRVInKSAlPiUNCiAgbXV0YXRlKGxvZ0VSID0gIGxvZzEwKDErRVIpKSAlPiUNCiAgc3RfYXNfc2YoKSAjIFJFQUxMWT8/Pw0KZXJZZWFyX3NmDQoNCiMgdGhlIHJhbmdlIHNob3VsZCBzdGlsbCB3b3JrIGZvciB0dGhlIGNvbG9ycw0KbWF4KGVyWWVhcl9zZiRsb2dFUikgIyBpcyB3aXRoaW4gDQplckNvbnRyb2wkZXJicmVha3MNCmBgYA0KDQpJIGRvbid0IHRoaW5rIEkgdXNlIHRoaXMsIGJ1dCBJIGRpZCBtYWtlIGEgZnVsbC13ZXJhaSBhZ2dyZWdhdGlvbg0KYGBge3J9DQojIGFnZ3JlZ2F0ZSB0byB3ZXJhaQ0KIyB0ZW1wIGFyZWEtd2VpZ2h0ZWQNCmFyZWFzIDwtIHRlbXBhbm51YWwgJT4lDQogIHN0X2dlb21ldHJ5KCkgJT4lDQogIHN0X2FyZWEoKSAlPiUNCiAgYXMubnVtZXJpYygpDQp0ZW1wVyA8LSBjYXRjaEFnZyA8LSBjYXRjaEFnZ1coc3RyaWN0ID0gdGVtcGFubnVhbCwgc3RyaWN0V2VpZ2h0cyA9IGFyZWFzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1lYW4sIHN1bW1hcnlQb2x5ID0gcmFtc2FyVzEpDQogIA0KaW51blcgPC0gYWdncmVnYXRlKGludW5hbm51YWwsIA0KICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gcmFtc2FyVzEsIA0KICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSwgbmEucm0gPSBUUlVFKQ0KDQpncHBXIDwtIGFnZ3JlZ2F0ZShncHBhbm51YWwsIA0KICAgICAgICAgICAgICAgICAgIGJ5ID0gcmFtc2FyVzEsIA0KICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSwgbmEucm0gPSBUUlVFKQ0KZXJXIDwtIGFnZ3JlZ2F0ZShlcmFubnVhbCwgDQogICAgICAgICAgICAgICAgICAgYnkgPSByYW1zYXJXMSwgDQogICAgICAgICAgICAgICAgICAgRlVOID0gc3VtLCBuYS5ybSA9IFRSVUUpDQoNCmBgYA0KDQojIyMgVG1hcCBQbG90cw0KTWFrZSBhIGZhY2V0dGVkIHRtYXANCg0KQWdhaW4sIGNhbiBJIGRvIHRoaXMgYnkgbW9kaWZ5aW5nIHdoYXQgSSBwYXNzIHRvIHRoZSBwbG90dGluZyBmdW5jdGlvbnM/IEFsbW9zdCBjZXJ0YWlubHkNCg0KVGhlIHVuaXRzIGFyZSB3ZWlyZCwgYmVjYXVzZSB0aGlzIGlzIGFkZGVkIHVwIGFjcm9zcyBiaW1vbnRocy4gSXQncyBuZWl0aGVyIHRoZSB0b3RhbCBvciB0aGUgYXZlcmFnZS5Ob3QgcmVhbGx5IHN1cmUgd2hhdCB0byBjYWxsIGl0DQoNCkNoYW5nZSB0aGUgdG1hcF9tb2RlKCkgZGVwZW5kaW5nIG9uIHRoZSBwdXJwb3NlLiBETyBOT1QgQ0hBTkdFIFRPIFZJRVcgQU5EIFRSWSBUTyBSVU4gSEVSRS4gSUYgWU9VIFdBTlQgVE8gVklFVywgQ0hBTkdFIEFORCBSVU4gSU4gQ09OU09MRS4gVGhlIG1hcmtkb3duIHdpbGwgcnVuIGl0LCBidXQgaW5jcmVkaWJseSBzbG93bHkuDQoNCkdQUA0KDQpgYGB7cn0NCnRtYXBfbW9kZSgncGxvdCcpDQoNCmdwcHlybGFiZWwgPC0gJ1RvdGFsIFllYXJseSBHUFAgKGtnIDAyKVxuYXQgbWF4IGJpbW9udGggZXh0ZW50cycNCg0KICBncHBBbm51YWxfdG0gPC0gZ3BwWWVhcl9zZiAlPiUNCiAgICBmaWx0ZXIoV2F0ZXJZZWFyICE9ICcyMDE0LTA2LTI5JykgJT4lICMgYmVjYXVzZSBhIDUtcGFuZWwgaXMgdWdseQ0KICAgIHRtX3NoYXBlKCkgKw0KICAgIHRtX2ZpbGwoY29sID0gJ2xvZ0dQUCcsDQogICAgICAgICAgICBwYWxldHRlID0gZ3BwQ29udHJvbCRncHBwYWwsDQogICAgICAgICAgICBicmVha3MgPSBncHBDb250cm9sJGdwcGJyZWFrcywNCiAgICAgICAgICAgIGxhYmVscyA9IGdwcENvbnRyb2wkZ3BwbGFiZWxzLA0KICAgICAgICAgICAgdGl0bGUgPSBncHB5cmxhYmVsKSArIA0KICAgIHRtX2ZhY2V0cyhieSA9ICdXYXRlclllYXInKQ0KICBncHBBbm51YWxfdG0NCmBgYA0KDQpFUg0KDQpgYGB7cn0NCmVyeXJsYWJlbCA8LSAnVG90YWwgWWVhcmx5IEVSIChrZyAwMilcbmF0IG1heCBiaW1vbnRoIGV4dGVudHMnDQogIA0KICBlckFubnVhbF90bSA8LSBlclllYXJfc2YgJT4lDQogICAgZmlsdGVyKFdhdGVyWWVhciAhPSAnMjAxNC0wNi0yOScpICU+JSAjIGJlY2F1c2UgYSA1LXBhbmVsIGlzIHVnbHkNCiAgICB0bV9zaGFwZSgpICsNCiAgICB0bV9maWxsKGNvbCA9ICdsb2dFUicsDQogICAgICAgICAgICBwYWxldHRlID0gZXJDb250cm9sJGVycGFsLA0KICAgICAgICAgICAgYnJlYWtzID0gZXJDb250cm9sJGVyYnJlYWtzLA0KICAgICAgICAgICAgbGFiZWxzID0gZXJDb250cm9sJGVybGFiZWxzLA0KICAgICAgICAgICAgdGl0bGUgPSBlcnlybGFiZWwpICsgDQogICAgdG1fZmFjZXRzKGJ5ID0gJ1dhdGVyWWVhcicpDQogIGVyQW5udWFsX3RtDQpgYGANCg0KDQojIyMgR0dQTE9UDQoNCmdwcA0KDQpgYGB7cn0NCmdwcEFubnVhbF9nZyA8LSBncHBZZWFyX3NmICU+JQ0KICAgIGZpbHRlcihXYXRlclllYXIgIT0gJzIwMTQtMDYtMjknKSAlPiUgIyBiZWNhdXNlIGEgNS1wYW5lbCBpcyB1Z2x5DQogICAgZ2dwbG90KCkgKw0KICAgIGdlb21fc2YobWFwcGluZyA9IGFlcyhmaWxsID0gbG9nR1BQKSwgY29sb3IgPSBOQSkgKw0KICAgIGNvb3JkX3NmKCkgKw0KICAgICMgQ2xvc2VzdCB0byB0aGUgdG1hcA0KICAgIHNjYWxlX2ZpbGxfc3RlcHNuKGNvbG9ycyA9IGdwcENvbnRyb2wkZ3BwcGFsLA0KICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGdwcENvbnRyb2wkZ3BwYnJlYWtzWzI6bGVuZ3RoKGdwcENvbnRyb2wkZ3BwYnJlYWtzKV0sDQogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhtaW4oZ3BwQ29udHJvbCRncHBicmVha3MpLCBtYXgoZ3BwQ29udHJvbCRncHBicmVha3MpKSwNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBncHBDb250cm9sJGdwcGxhYmVscywNCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICdsZWdlbmQnLA0KICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBncHB5cmxhYmVsKSArDQogICAgZmFjZXRfd3JhcCh2YXJzKFdhdGVyWWVhcikpDQogIGdwcEFubnVhbF9nZw0KYGBgDQoNCkVSDQpgYGB7cn0NCmVyQW5udWFsX2dnIDwtIGVyWWVhcl9zZiAlPiUNCiAgICBmaWx0ZXIoV2F0ZXJZZWFyICE9ICcyMDE0LTA2LTI5JykgJT4lICMgYmVjYXVzZSBhIDUtcGFuZWwgaXMgdWdseQ0KICAgIGdncGxvdCgpICsNCiAgICBnZW9tX3NmKG1hcHBpbmcgPSBhZXMoZmlsbCA9IGxvZ0VSKSwgY29sb3IgPSBOQSkgKw0KICAgIGNvb3JkX3NmKCkgKw0KICAgICMgQ2xvc2VzdCB0byB0aGUgdG1hcA0KICAgIHNjYWxlX2ZpbGxfc3RlcHNuKGNvbG9ycyA9IGVyQ29udHJvbCRlcnBhbCwNCiAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBlckNvbnRyb2wkZXJicmVha3NbMjpsZW5ndGgoZXJDb250cm9sJGVyYnJlYWtzKV0sDQogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhtaW4oZXJDb250cm9sJGVyYnJlYWtzKSwgbWF4KGVyQ29udHJvbCRlcmJyZWFrcykpLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGVyQ29udHJvbCRlcmxhYmVscywNCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICdsZWdlbmQnLA0KICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBlcnlybGFiZWwpICsNCiAgICBmYWNldF93cmFwKHZhcnMoV2F0ZXJZZWFyKSkNCiAgZXJBbm51YWxfZ2cNCmBgYA0KDQpTdGFjayAzIHllYXJzIG9mIGdwcCBhbmQgRVIgdG9nZXRoZXIgZm9yIHRoZSBkb2N1bWVudA0KDQpgYGB7cn0NCmdwcEFubnVhbF9nZzMgPC0gZ3BwWWVhcl9zZiAlPiUNCiAgICBmaWx0ZXIoV2F0ZXJZZWFyICE9ICcyMDE0LTA2LTI5JyAmIFdhdGVyWWVhciAhPSAnMjAxOC0wNi0yOScpICU+JSAjIGJlY2F1c2UgYSA1LXBhbmVsIGlzIHVnbHkNCiAgICBnZ3Bsb3QoKSArDQogICAgZ2VvbV9zZihtYXBwaW5nID0gYWVzKGZpbGwgPSBsb2dHUFApLCBjb2xvciA9IE5BKSArDQogICAgY29vcmRfc2YoKSArDQogICAgIyBDbG9zZXN0IHRvIHRoZSB0bWFwDQogICAgc2NhbGVfZmlsbF9zdGVwc24oY29sb3JzID0gZ3BwQ29udHJvbCRncHBwYWwsDQogICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gZ3BwQ29udHJvbCRncHBicmVha3NbMjpsZW5ndGgoZ3BwQ29udHJvbCRncHBicmVha3MpXSwNCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKG1pbihncHBDb250cm9sJGdwcGJyZWFrcyksIG1heChncHBDb250cm9sJGdwcGJyZWFrcykpLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGdwcENvbnRyb2wkZ3BwbGFiZWxzLA0KICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gJ2xlZ2VuZCcsDQogICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IGdwcHlybGFiZWwpICsNCiAgICBmYWNldF9ncmlkKFdhdGVyWWVhcn4uKSArIA0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKQ0KICAjIGdwcEFubnVhbF9nZzMgDQogIA0KICBlckFubnVhbF9nZzMgPC0gZXJZZWFyX3NmICU+JQ0KICAgIGZpbHRlcihXYXRlclllYXIgIT0gJzIwMTQtMDYtMjknICYgV2F0ZXJZZWFyICE9ICcyMDE4LTA2LTI5JykgJT4lICMgYmVjYXVzZSBhIDUtcGFuZWwgaXMgdWdseQ0KICAgIGdncGxvdCgpICsNCiAgICBnZW9tX3NmKG1hcHBpbmcgPSBhZXMoZmlsbCA9IGxvZ0VSKSwgY29sb3IgPSBOQSkgKw0KICAgIGNvb3JkX3NmKCkgKw0KICAgICMgQ2xvc2VzdCB0byB0aGUgdG1hcA0KICAgIHNjYWxlX2ZpbGxfc3RlcHNuKGNvbG9ycyA9IGVyQ29udHJvbCRlcnBhbCwNCiAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBlckNvbnRyb2wkZXJicmVha3NbMjpsZW5ndGgoZXJDb250cm9sJGVyYnJlYWtzKV0sDQogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhtaW4oZXJDb250cm9sJGVyYnJlYWtzKSwgbWF4KGVyQ29udHJvbCRlcmJyZWFrcykpLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGVyQ29udHJvbCRlcmxhYmVscywNCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICdsZWdlbmQnLA0KICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBlcnlybGFiZWwpICsNCiAgICBmYWNldF9ncmlkKFdhdGVyWWVhcn4uKSArIA0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKQ0KICAjIGVyQW5udWFsX2dnMw0KDQogIGFubnVhbEdQUEVSIDwtIGdncHVicjo6Z2dhcnJhbmdlKGdwcEFubnVhbF9nZzMgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICd0b3AnKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2dyZXkoYmFzZV9zaXplID0gOCkgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjMsICdjbScpKSwgDQogICAgICAgICAgICAgICAgICAgIGVyQW5udWFsX2dnMyArIA0KICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gJ3RvcCcpKSArDQogICAgICAgICAgICAgICAgICAgICAgdGhlbWVfZ3JleShiYXNlX3NpemUgPSA4KSArIA0KICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMywgJ2NtJykpLA0KICAgICAgICAgICAgICAgICAgICBuY29sID0gMiwgbnJvdyA9IDEpDQogIGFubnVhbEdQUEVSDQpgYGANCg0KUHJpbnQgb3V0IHRoZSBnZ3Bsb3RzIGZvciB0aGUgZG9jDQoNCmBgYHtyfQ0KICMgSnVzdCBwcmludCB0aGUgZ2dwbG90cw0KICAjIENhbiBJIHByaW50IHRob3NlPw0KICBwZGYoZmlsZS5wYXRoKHNjcmlwdE91dCwgJ1dlcmFpX2dnX0FubnVhbC5wZGYnKSwgDQogICAgICBvbmVmaWxlID0gRkFMU0UsIGhlaWdodCA9IDEyLzIuNTQsIHdpZHRoID0gMTYvMi41NCwgdXNlRGluZ2JhdHMgPSBGQUxTRSkNCiAgcHJpbnQoYW5udWFsR1BQRVIpDQogIGRldi5vZmYoKQ0KICANCiAgcG5nKGZpbGUucGF0aChzY3JpcHRPdXQsICdXZXJhaV9nZ19Bbm51YWwucG5nJyksIA0KICAgICAgaGVpZ2h0ID0gMTIvMi41NCwgd2lkdGggPSAxNi8yLjU0LCB1bml0cyA9ICdpbicsIHJlcyA9IDMwMCkNCiAgcHJpbnQoYW5udWFsR1BQRVIpDQogIGRldi5vZmYoKQ0KICANCg0KYGBgDQoNCg==